Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
5.57% covered (danger)
5.57%
1213 / 21786
7.73% covered (danger)
7.73%
15 / 194
CRAP
0.00% covered (danger)
0.00%
0 / 1
PaymentController
5.55% covered (danger)
5.55%
1210 / 21783
7.73% covered (danger)
7.73%
15 / 194
23714159.98
0.00% covered (danger)
0.00%
0 / 1
 beforeFilter
0.00% covered (danger)
0.00%
0 / 114
0.00% covered (danger)
0.00%
0 / 1
380
 index
100.00% covered (success)
100.00%
25 / 25
100.00% covered (success)
100.00%
1 / 1
2
 getWPPaymentResult
89.43% covered (success)
89.43%
457 / 511
0.00% covered (danger)
0.00%
0 / 1
155.19
 worldpay_error_log_set
95.71% covered (success)
95.71%
134 / 140
0.00% covered (danger)
0.00%
0 / 1
28
 complete
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
4
 pointsComplete
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
1 / 1
2
 callback
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 checkCallBack
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
42
 savePdataLog
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 t_start
100.00% covered (success)
100.00%
38 / 38
100.00% covered (success)
100.00%
1 / 1
5
 charge_company_select
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 z_start
96.91% covered (success)
96.91%
157 / 162
0.00% covered (danger)
0.00%
0 / 1
64
 payment_credit_register_complete
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
1 / 1
4
 coupon_payment_credit_charge_complete
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 payment_credit_charge_complete
100.00% covered (success)
100.00%
58 / 58
100.00% covered (success)
100.00%
1 / 1
7
 payment_credit_retry_complete
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
1 / 1
4
 payment_credit_change_complete
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
5
 handleCreditResponseError
100.00% covered (success)
100.00%
27 / 27
100.00% covered (success)
100.00%
1 / 1
16
 zeuspay
0.00% covered (danger)
0.00%
0 / 2022
0.00% covered (danger)
0.00%
0 / 1
298662
 saveStep
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
2
 corporateZeuspay
0.00% covered (danger)
0.00%
0 / 1196
0.00% covered (danger)
0.00%
0 / 1
89102
 update_card_fail_flg
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
1 / 1
8
 _error_log_set
81.68% covered (success)
81.68%
107 / 131
0.00% covered (danger)
0.00%
0 / 1
32.82
 free_digest_member_t_start
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
 coupon_form
95.00% covered (success)
95.00%
76 / 80
0.00% covered (danger)
0.00%
0 / 1
15
 payment_credit_register
0.00% covered (danger)
0.00%
0 / 86
0.00% covered (danger)
0.00%
0 / 1
342
 zeus_credit_register
0.00% covered (danger)
0.00%
0 / 166
0.00% covered (danger)
0.00%
0 / 1
756
 checkIfChargedAfterChallenge
0.00% covered (danger)
0.00%
0 / 60
0.00% covered (danger)
0.00%
0 / 1
1406
 wp_credit_register
0.00% covered (danger)
0.00%
0 / 87
0.00% covered (danger)
0.00%
0 / 1
240
 payment_credit_register_confirm
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 zeus_credit_register_confirm
0.00% covered (danger)
0.00%
0 / 25
0.00% covered (danger)
0.00%
0 / 1
72
 wp_credit_register_confirm
0.00% covered (danger)
0.00%
0 / 182
0.00% covered (danger)
0.00%
0 / 1
1190
 paypal_payment_credit_register_confirm
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
6
 paypal_payment_credit_register_process
0.00% covered (danger)
0.00%
0 / 100
0.00% covered (danger)
0.00%
0 / 1
462
 sp_paypal_payment_credit_register_process
0.00% covered (danger)
0.00%
0 / 34
0.00% covered (danger)
0.00%
0 / 1
90
 wp_credit_register_form
0.00% covered (danger)
0.00%
0 / 45
0.00% covered (danger)
0.00%
0 / 1
6
 payment_credit_change
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
30
 zeus_credit_change
0.00% covered (danger)
0.00%
0 / 88
0.00% covered (danger)
0.00%
0 / 1
1260
 paypal_payment_credit_change_process
0.00% covered (danger)
0.00%
0 / 26
0.00% covered (danger)
0.00%
0 / 1
42
 wp_credit_change
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
42
 wp_credit_change_form
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
20
 payment_credit_charge
0.00% covered (danger)
0.00%
0 / 28
0.00% covered (danger)
0.00%
0 / 1
42
 zeus_credit_charge
0.00% covered (danger)
0.00%
0 / 329
0.00% covered (danger)
0.00%
0 / 1
6006
 wp_credit_charge
0.00% covered (danger)
0.00%
0 / 64
0.00% covered (danger)
0.00%
0 / 1
380
 payment_credit_charge_confirm
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 retrial_confiscate_coins
0.00% covered (danger)
0.00%
0 / 41
0.00% covered (danger)
0.00%
0 / 1
210
 zeus_credit_charge_confirm
0.00% covered (danger)
0.00%
0 / 55
0.00% covered (danger)
0.00%
0 / 1
420
 wp_credit_charge_confirm
0.00% covered (danger)
0.00%
0 / 186
0.00% covered (danger)
0.00%
0 / 1
1260
 paypal_payment_credit_charge_confirm
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
12
 wp_credit_charge_form
0.00% covered (danger)
0.00%
0 / 54
0.00% covered (danger)
0.00%
0 / 1
156
 paypal_payment_credit_charge_process
0.00% covered (danger)
0.00%
0 / 75
0.00% covered (danger)
0.00%
0 / 1
306
 payment_credit_retry
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
6
 zeus_credit_retry
0.00% covered (danger)
0.00%
0 / 205
0.00% covered (danger)
0.00%
0 / 1
2162
 wp_credit_retry
0.00% covered (danger)
0.00%
0 / 47
0.00% covered (danger)
0.00%
0 / 1
156
 payment_credit_retry_confirm
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 zeus_credit_retry_confirm
0.00% covered (danger)
0.00%
0 / 26
0.00% covered (danger)
0.00%
0 / 1
110
 wp_credit_retry_confirm
0.00% covered (danger)
0.00%
0 / 182
0.00% covered (danger)
0.00%
0 / 1
1122
 paypal_payment_credit_retry_confirm
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
6
 wp_credit_retry_form
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
42
 paypal_payment_credit_retry_process
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
56
 checkUser
0.00% covered (danger)
0.00%
0 / 51
0.00% covered (danger)
0.00%
0 / 1
812
 formDataValidation
0.00% covered (danger)
0.00%
0 / 30
0.00% covered (danger)
0.00%
0 / 1
650
 withdraw
0.00% covered (danger)
0.00%
0 / 45
0.00% covered (danger)
0.00%
0 / 1
182
 withdraw_confirm
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
6
 checkToken
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 unsetToken
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 createPaymentTransaction
0.00% covered (danger)
0.00%
0 / 201
0.00% covered (danger)
0.00%
0 / 1
7310
 getPaymentTransaction
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 mobapp_payment_credit_register_receivable
0.00% covered (danger)
0.00%
0 / 36
0.00% covered (danger)
0.00%
0 / 1
90
 mobapp_credit_change
0.00% covered (danger)
0.00%
0 / 67
0.00% covered (danger)
0.00%
0 / 1
600
 mobapp_wp_credit_change
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
6
 mobapp_wp_credit_change_form
0.00% covered (danger)
0.00%
0 / 33
0.00% covered (danger)
0.00%
0 / 1
30
 mobapp_credit_change_form
0.00% covered (danger)
0.00%
0 / 76
0.00% covered (danger)
0.00%
0 / 1
380
 mobapp_paypal_credit_change_process
0.00% covered (danger)
0.00%
0 / 32
0.00% covered (danger)
0.00%
0 / 1
12
 mobapp_credit_retry
0.00% covered (danger)
0.00%
0 / 202
0.00% covered (danger)
0.00%
0 / 1
1892
 mobapp_credit_retry_form
0.00% covered (danger)
0.00%
0 / 97
0.00% covered (danger)
0.00%
0 / 1
306
 mobapp_wp_credit_retry
0.00% covered (danger)
0.00%
0 / 33
0.00% covered (danger)
0.00%
0 / 1
30
 mobapp_wp_credit_retry_form
0.00% covered (danger)
0.00%
0 / 41
0.00% covered (danger)
0.00%
0 / 1
72
 mobapp_wp_credit_retry_confirm
0.00% covered (danger)
0.00%
0 / 182
0.00% covered (danger)
0.00%
0 / 1
992
 mobapp_credit_retry_confirm
0.00% covered (danger)
0.00%
0 / 43
0.00% covered (danger)
0.00%
0 / 1
110
 mobapp_paypal_credit_retry_confirm
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
6
 mobapp_paypal_credit_retry_process
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 1
156
 mobapp_credit_register_trial_notice
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
2
 mobapp_credit_register
0.00% covered (danger)
0.00%
0 / 109
0.00% covered (danger)
0.00%
0 / 1
182
 mobapp_credit_register_form
0.00% covered (danger)
0.00%
0 / 141
0.00% covered (danger)
0.00%
0 / 1
462
 sp_credit_register_form
0.00% covered (danger)
0.00%
0 / 40
0.00% covered (danger)
0.00%
0 / 1
42
 mobapp_credit_register_confirm
0.00% covered (danger)
0.00%
0 / 25
0.00% covered (danger)
0.00%
0 / 1
56
 mobapp_paypal_credit_register_confirm
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
6
 mobapp_paypal_credit_register_process
0.00% covered (danger)
0.00%
0 / 88
0.00% covered (danger)
0.00%
0 / 1
272
 mobapp_credit_register_notice_to_user
0.00% covered (danger)
0.00%
0 / 138
0.00% covered (danger)
0.00%
0 / 1
1482
 mobapp_credit_register_native_plan
0.00% covered (danger)
0.00%
0 / 89
0.00% covered (danger)
0.00%
0 / 1
420
 mobapp_credit_register_questionnaire
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 mobapp_wp_credit
0.00% covered (danger)
0.00%
0 / 78
0.00% covered (danger)
0.00%
0 / 1
210
 mobapp_wp_credit_register
0.00% covered (danger)
0.00%
0 / 72
0.00% covered (danger)
0.00%
0 / 1
272
 mobapp_wp_credit_register_form
0.00% covered (danger)
0.00%
0 / 28
0.00% covered (danger)
0.00%
0 / 1
12
 mobapp_wp_credit_register_confirm
0.00% covered (danger)
0.00%
0 / 176
0.00% covered (danger)
0.00%
0 / 1
1056
 mobapp_credit_charge
0.00% covered (danger)
0.00%
0 / 288
0.00% covered (danger)
0.00%
0 / 1
4556
 mobapp_credit_charge_form
0.00% covered (danger)
0.00%
0 / 325
0.00% covered (danger)
0.00%
0 / 1
5112
 mobapp_wp_credit_charge
0.00% covered (danger)
0.00%
0 / 60
0.00% covered (danger)
0.00%
0 / 1
342
 mobapp_wp_credit_charge_form
0.00% covered (danger)
0.00%
0 / 57
0.00% covered (danger)
0.00%
0 / 1
210
 mobapp_wp_credit_charge_confirm
0.00% covered (danger)
0.00%
0 / 184
0.00% covered (danger)
0.00%
0 / 1
1190
 mobapp_credit_charge_confirm
0.00% covered (danger)
0.00%
0 / 76
0.00% covered (danger)
0.00%
0 / 1
552
 mobapp_paypal_credit_charge_confirm
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
6
 mobapp_paypal_credit_charge_process
0.00% covered (danger)
0.00%
0 / 76
0.00% covered (danger)
0.00%
0 / 1
210
 mobappSetUpTransaction
0.00% covered (danger)
0.00%
0 / 33
0.00% covered (danger)
0.00%
0 / 1
210
 checkTokenMobapp
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 unsetTokenMobapp
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 getUserData
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
6
 zeus_card_process_mobapp
0.00% covered (danger)
0.00%
0 / 198
0.00% covered (danger)
0.00%
0 / 1
5402
 handleCreditResponseErrorMobapp
0.00% covered (danger)
0.00%
0 / 32
0.00% covered (danger)
0.00%
0 / 1
342
 failure_family
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 sp_failure_family
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 getUserId
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
110
 decodeSendPointData
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
30
 failureFamily
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
12
 getAndSetCardInfo
0.00% covered (danger)
0.00%
0 / 30
0.00% covered (danger)
0.00%
0 / 1
156
 setPaymentViewVars
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 failure_settlement
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 mobapp_failure_settlement
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
42
 sp_failure_settlement
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
20
 getWPUserData
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
6
 updatePaymentTransaction
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
42
 getHostedPage
0.00% covered (danger)
0.00%
0 / 319
0.00% covered (danger)
0.00%
0 / 1
8556
 deleteUserToken
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
 memcacheWPPayment
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
90
 memcacheCardType
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 processWPPayment
0.00% covered (danger)
0.00%
0 / 1187
0.00% covered (danger)
0.00%
0 / 1
105300
 mobappGetUserData
0.00% covered (danger)
0.00%
0 / 90
0.00% covered (danger)
0.00%
0 / 1
702
 getRetryPaymentData
0.00% covered (danger)
0.00%
0 / 120
0.00% covered (danger)
0.00%
0 / 1
756
 changePaymentPlanIfTelecomUser
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
20
 notice_coupon_code_plan
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 notice_coupon_code_plan_change
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
6
 complimentaryPlanValidation
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
30
 updateUserCardCompanyToZeus
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 slackWPErrorPostMsg
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
1
 ifComPlanUser
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
56
 getCorporatePaymentPlan
0.00% covered (danger)
0.00%
0 / 33
0.00% covered (danger)
0.00%
0 / 1
110
 mobapp_corporate_register_card
0.00% covered (danger)
0.00%
0 / 80
0.00% covered (danger)
0.00%
0 / 1
272
 slackZeusErrorPostMsg
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
6
 processPayPalPayment
0.00% covered (danger)
0.00%
0 / 613
0.00% covered (danger)
0.00%
0 / 1
11772
 addCoinRewardForReenroll
0.00% covered (danger)
0.00%
0 / 45
0.00% covered (danger)
0.00%
0 / 1
182
 paypalSaveBillingAgreement
0.00% covered (danger)
0.00%
0 / 302
0.00% covered (danger)
0.00%
0 / 1
4032
 setSupportPayPal
0.00% covered (danger)
0.00%
0 / 42
0.00% covered (danger)
0.00%
0 / 1
272
 sms_questionnaire
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 restrictForTrialNotConducted
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
20
 zeuspayGetChallenge
0.00% covered (danger)
0.00%
0 / 443
0.00% covered (danger)
0.00%
0 / 1
22952
 reportZeusChallengeResponse
0.00% covered (danger)
0.00%
0 / 258
0.00% covered (danger)
0.00%
0 / 1
5852
 sendZeusResponseSlackMessage
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
12
 processRedirection
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
 getAfteeHostedPage
0.00% covered (danger)
0.00%
0 / 238
0.00% covered (danger)
0.00%
0 / 1
3906
 getAfteePaymentResult
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
30
 afteeAuthentication
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 processAfteePayment
0.00% covered (danger)
0.00%
0 / 721
0.00% covered (danger)
0.00%
0 / 1
33672
 slackAfteePErrorPostMsg
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
2
 handleAfteeAuthenticationSuccess
0.00% covered (danger)
0.00%
0 / 356
0.00% covered (danger)
0.00%
0 / 1
10920
 handleAfteeDirectPaymentSuccess
0.00% covered (danger)
0.00%
0 / 497
0.00% covered (danger)
0.00%
0 / 1
8190
 sendNatGeoEbookPurchaseEmailSlack
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
2
 sendEbookPurchaseEmailSlack
0.00% covered (danger)
0.00%
0 / 82
0.00% covered (danger)
0.00%
0 / 1
380
 isForTrialReenrollment
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
12
 checkZeusChallengeResponse
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 setPaymentPlanDetails
0.00% covered (danger)
0.00%
0 / 56
0.00% covered (danger)
0.00%
0 / 1
182
 corpIndividualData
0.00% covered (danger)
0.00%
0 / 118
0.00% covered (danger)
0.00%
0 / 1
702
 corporate_change_individual_card_payment
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
20
 corp_user_change_personal_card
0.00% covered (danger)
0.00%
0 / 135
0.00% covered (danger)
0.00%
0 / 1
2070
 paypal_student_discount_user_change_card
0.00% covered (danger)
0.00%
0 / 294
0.00% covered (danger)
0.00%
0 / 1
2550
 student_discount_user_change_card
0.00% covered (danger)
0.00%
0 / 167
0.00% covered (danger)
0.00%
0 / 1
2256
 mobapp_corporate_change_individual_card_payment
0.00% covered (danger)
0.00%
0 / 267
0.00% covered (danger)
0.00%
0 / 1
3306
 processChildReceivablePayment
0.00% covered (danger)
0.00%
0 / 117
0.00% covered (danger)
0.00%
0 / 1
272
 processChildPaypalPayment
0.00% covered (danger)
0.00%
0 / 224
0.00% covered (danger)
0.00%
0 / 1
420
 processChildAfteePayment
0.00% covered (danger)
0.00%
0 / 233
0.00% covered (danger)
0.00%
0 / 1
600
 mobapp_credit_retry_complete
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
42
 setLitePaymentInfoView
0.00% covered (danger)
0.00%
0 / 31
0.00% covered (danger)
0.00%
0 / 1
42
 liteUserAddCoinRewardForReenroll
0.00% covered (danger)
0.00%
0 / 45
0.00% covered (danger)
0.00%
0 / 1
56
 processChangePlan
0.00% covered (danger)
0.00%
0 / 206
0.00% covered (danger)
0.00%
0 / 1
2162
 processChildWithdrawal
0.00% covered (danger)
0.00%
0 / 77
0.00% covered (danger)
0.00%
0 / 1
240
 paypal_payment_change_plan_process
0.00% covered (danger)
0.00%
0 / 566
0.00% covered (danger)
0.00%
0 / 1
4830
 zeus_payment_change_plan
0.00% covered (danger)
0.00%
0 / 89
0.00% covered (danger)
0.00%
0 / 1
210
 payment_credit_register_receivable
0.00% covered (danger)
0.00%
0 / 47
0.00% covered (danger)
0.00%
0 / 1
156
 createCorporateIndividualPayment
0.00% covered (danger)
0.00%
0 / 130
0.00% covered (danger)
0.00%
0 / 1
812
 getDefaultPlanId
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
56
 selectCorpType
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
20
 createLitePlanTransaction
0.00% covered (danger)
0.00%
0 / 53
0.00% covered (danger)
0.00%
0 / 1
210
 applyCouponPayment
0.00% covered (danger)
0.00%
0 / 73
0.00% covered (danger)
0.00%
0 / 1
756
 setCouponUseData
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
30
 paypalWebhook
0.00% covered (danger)
0.00%
0 / 74
0.00% covered (danger)
0.00%
0 / 1
306
 createChocottoPlanTransaction
0.00% covered (danger)
0.00%
0 / 45
0.00% covered (danger)
0.00%
0 / 1
132
 stripepay
0.00% covered (danger)
0.00%
0 / 32
0.00% covered (danger)
0.00%
0 / 1
72
 stripepay_manual
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 handleStripePaymentResult
0.00% covered (danger)
0.00%
0 / 1777
0.00% covered (danger)
0.00%
0 / 1
202050
 stripe_error_log_set
0.00% covered (danger)
0.00%
0 / 119
0.00% covered (danger)
0.00%
0 / 1
650
 slackStripeErrorPostMsg
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
6
 getStripeHostedPage
0.00% covered (danger)
0.00%
0 / 261
0.00% covered (danger)
0.00%
0 / 1
5402
 sendStripeResponseSlackMessage
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
30
 updateUserToken
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2App::uses('AppController', 'Controller');
3App::uses('Folder', 'Utility');
4App::uses('File', 'Utility');
5
6class PaymentController extends AppController {
7    public $uses = array(
8        'User',
9        'CourseMaster',
10        'PaymentLogs',
11        'UsersCourses',
12        'UsersPoints',
13        'PaymentLog',
14        'LessonOnairsLog',
15        'Payment',
16        'PaymentTransaction',
17        'RecurringLog',
18        'ZPaymentSucceeded',
19        'UsersEmailConfirm',
20        'UsersRegistrationQuestion',
21        'PaymentReceivable',
22        'TextbookSale',
23        'UsersPointHistory',
24        'FamilyPlanList',
25        'UsersPoint',
26        'PaymentPlanPrice',
27        'Currency',
28        'CorporatePaymentMemberReceivable',
29        'Corporate',
30        'UserWithdrawReenrollCampaign',
31        'UserStatusChangeLog',
32        'UsersReferral',
33        'UsersCoupon',
34        'UsersCouponV1',
35        'CoinBox',
36        'ComplimentaryCode',
37        'CorporatesPaymentReceivable',
38        'CorporateDiscountRate',
39        'LessonOnairsLog',
40        'CorporateScheduledDeactivation',
41        'CorporatePaymentIdLog',
42        'NativeOption',
43        'UsersDeactivationEnquate',
44        'LessonSchedule',
45        'FamilyDeactivationLog',
46        'UsersFamilyAccount',
47        'CampaignMaster',
48        'PhoneVerifyCheckLog',
49        'CountryCode',
50        'Timezone',
51        'CorporateActivationManagement',
52        'CorporateActivationManagementLog',
53        'TextbookSalesAddToCartItem',
54        'CorporateCategory',
55        'UsersDetail',
56        'TextbookSalesAddToCartItem',
57        'UserDiscountOptionsTerm',
58        'DiscountOptionsSettlementHistory',
59        'DiscountOptionsPrice',
60        'UserOptionChangeLog',
61        'FileStorage',
62        'Payment',
63        'StudentDiscountApplicationForm',
64        'RyugakuSchoolPayment',
65        'RyugakuAdminEstimateRequest',
66        'ZeusAccountBlock',
67        'IpBlock',
68        'RyugakuAdminEstimateRequestPricing',
69        'ContinuationRewardPoint',
70        'CompCodeUsage'
71    );
72    public $memcache = null;
73    public $helpers = array('Html', 'Form');
74    public $components = array("ZCharge");
75    public function beforeFilter() {
76        parent::beforeFilter();
77        //instantiate slack
78        $this->mySlack = new mySlack();
79        //set slack channel
80        $this->slackChannel = myTools::checkChannel('#nc-settlement', '#nc-settlement-dev');
81        $this->Auth->allow(array(
82            'callback',
83            'zeuspay',
84            'mobapp_credit_change',
85            'mobapp_credit_change_form',
86            'mobapp_credit_change_complete',
87            'mobapp_credit_register',
88            'mobapp_credit_register_form',
89            'mobapp_credit_charge',
90            'mobapp_credit_charge_form',
91            'mobapp_corporate_change_individual_card_payment',
92            'mobapp_corporate_change_individual_card_payment_form',
93            'mobapp_credit_charge_confirm',
94            'mobapp_credit_register_confirm',
95            'mobapp_credit_register_notice_to_user',
96            'mobapp_credit_register_native_plan',
97            'mobapp_credit_register_questionnaire',
98            'mobapp_credit_retry',
99            'mobapp_credit_retry_form',
100            'mobapp_credit_retry_confirm',
101            'mobapp_failure_settlement',
102            'failureFamily',
103            'getWPPaymentResult',
104            'mobapp_wp_credit_change',
105            'mobapp_wp_credit_change_form',
106            'mobapp_wp_credit_retry',
107            'mobapp_wp_credit_retry_form',
108            'mobapp_wp_credit_retry_confirm',
109            'mobapp_wp_credit_charge',
110            'mobapp_wp_credit_charge_form',
111            'mobapp_wp_credit_charge_confirm',
112            'mobapp_wp_credit_register',
113            'mobapp_wp_credit_register_form',
114            'mobapp_wp_credit_register_confirm',
115            'wp_card_has_issue',
116            'getHostedPage',
117            'notice_coupon_code_plan',
118            'notice_coupon_code_plan_change',
119            'mobapp_corporate_register_card',
120            'mobapp_paypal_credit_register_confirm',
121            'mobapp_paypal_credit_register_process',
122            'mobapp_paypal_credit_change_process',
123            'mobapp_paypal_credit_charge_confirm',
124            'mobapp_paypal_credit_charge_process',
125            'mobapp_paypal_credit_retry_confirm',
126            'mobapp_paypal_credit_retry_process',
127            'mobapp_credit_register_trial_notice',
128            'mobapp_wp_credit',
129            'zeuspayGetChallenge',
130            'handleAfteeAuthenticationSuccess',
131            'getAfteePaymentResult',
132            'afteeAuthentication',
133            'getAfteeHostedPage',
134            'handleAfteeDirectPaymentSuccess',
135            'checkZeusChallengeResponse',
136            'reportZeusChallengeResponse',
137            'corp_user_change_personal_card',
138            'mobapp_credit_retry_complete',
139            'processChangePlan',
140            'createCorporateIndividualPayment',
141            'applyCouponPayment',
142            'mobapp_payment_credit_register_receivable',
143            'student_discount_user_change_card',
144            'paypal_student_discount_user_change_card',
145            'paypalWebhook',
146            'stripepay',
147            'getStripeHostedPage',
148            'stripepay_manual'
149        ));
150        $this->set('referer', $this->referer());
151        $this->set('page_css', 'payment');
152        //memcache
153        $this->memcache = new myMemcached();
154
155        $joinNativeOption = (isset($this->request->query['joinNativeOption']) && $this->request->query['joinNativeOption']) ? true : false;
156        $purchaseCoinTextbookNativeOptionAftee = (isset($this->request->params['action']) && $this->request->params['action'] == 'handleAfteeDirectPaymentSuccess') ? true : false;
157
158        // redirect to failure_family if family plan
159        if (!empty($this->sharedUserData['User']['parent_id']) && $this->action != 'failure_family' && !$joinNativeOption && !$purchaseCoinTextbookNativeOptionAftee) {
160            return $this->redirect(myTools::getUrl() . '/payment/failure_family');
161        } elseif ($this->parentId && $this->action != 'failureFamily' && !$joinNativeOption && !$purchaseCoinTextbookNativeOptionAftee) {
162            return $this->redirect(myTools::getUrl() . '/user/mobapp/payment/failure_family?'  . $_SERVER['QUERY_STRING']);    
163        }
164
165        $action = $this->params['action'];
166        $mobappActions = array(
167            'mobapp_credit_change',
168            'mobapp_credit_change_form',
169            'mobapp_credit_retry',
170            'mobapp_credit_retry_confirm',
171            'mobapp_credit_retry_form',
172            'mobapp_credit_register_form',
173            'mobapp_credit_register_confirm',
174            'mobapp_credit_charge',
175            'mobapp_credit_charge_form',
176            'mobapp_corporate_change_individual_card_payment',
177            'mobapp_corporate_change_individual_card_payment_form',
178            'mobapp_credit_charge_confirm'
179        );
180
181        $mobappFirstPages = array('mobapp_credit_retry', 'mobapp_credit_change', 'mobapp_credit_register', 'mobapp_credit_charge', 'mobapp_credit_charge','corporate_change_individual_card_payment');
182        if (in_array($action, $mobappFirstPages)) {
183            myTools::setTokenSession();
184        }
185
186        //*set $_GET['token'] if missing for mobapp
187        myTools::checkMobappToken($action, $mobappActions);
188
189        //fetch monthly detail
190        $monthly_price = $this->User->getMonthlyPayment(array(
191            'query' => $this->request->query,
192            'cookie' => $this->Cookie->read('currency_cookie')
193        ));
194
195        $this->set($monthly_price);
196        //save currency in cookie
197        $this->Cookie->write('currency_cookie', $monthly_price['currency']);
198        
199        // - NC_8454 show maintenance error when it's zeus maintenance time
200        $zeusMaintenance = false;
201        if (myTools::zeusMaintenancePeriod()){
202            $zeusMaintenance = true;
203        }
204        $this->set('zeus_maintenance', $zeusMaintenance);
205
206        // check if allowed aftee
207        $enableAftee = (isset($this->localizeDir) && $this->localizeDir == 'zh-tw') ? 1 : 0;
208        if (isset($this->sharedUserData['User']['currency_code']) && $this->sharedUserData['User']['currency_code'] != 'TWD') {
209            $enableAftee = 0;
210        }
211        $this->set('enableAftee', false);
212
213    }
214
215    public function index() {
216        $this->savePdataLog(1);
217        $data = $this->checkCallBack();
218        if ($data) {
219            //insert db payment log
220            $this->Payment->create();
221            $this->Payment->set(array(
222                'user_id' => $this->Auth->user('id'),
223                'type_id' => 1,
224                'pay_kbn' => 1,
225                'reference_id' => $data['txn_id'],
226                'amount' => $data['mc_gross'],
227                'course_id' => $data['item_number1'],
228                'param1' => json_encode($data)
229            ));
230            $this->Payment->save();
231
232            //insert db points
233            $courseMasterData = $this->CourseMaster->findById($data['item_number1']);
234            $courseMaster = $courseMasterData['CourseMaster'];
235            // NC-5007
236            $pointParams = array(
237                'userId' => $this->Auth->user('id'),
238                'point' => $courseMaster['add_point'],
239                'kbn' => 2,
240                'kbnType' => 1, // add coin
241                'coinType' => 2, // service point
242            );
243            $this->UsersPoint->performPointTransaction($pointParams);
244
245            //thank you page
246            return $this->redirect(myTools::getUrl() . '/payment/points/complete');
247        }
248    }
249
250    /**
251     * NC-4770: Receive the payment result from worldpay
252     * @param $_POST data
253     */
254    public function getWPPaymentResult() {
255        $this->autoRender = $this->autoLayout = false;
256
257        $this->log('fetched wp result --> ' . json_encode($_POST), 'wp_debug');
258
259        // get data
260        $data = $_POST;
261
262        // return if empty data
263        if (!$data) {
264            $this->log(__METHOD__ . ' Worldpay: Empty kickback data --> ' . json_encode($data), 'wp_debug');
265            return "[OK]"; 
266            //NJ-69126 exit; I used return to force Stop Unit Test to process below and if use Exit it will stop the whole process also
267        }
268
269        // set variables
270        $orderCode = isset($data['OrderCode']) ? $data['OrderCode'] : null;
271        $paymentStatusName = isset($data['PaymentStatus']) ? $data['PaymentStatus'] : '';
272        $dataJson = json_encode($data);
273
274        // get payment transaction data 
275        $paymentTransactionData = $this->PaymentTransaction->getWPPaymentTransaction($orderCode);
276        $userId = $paymentTransactionData['user_id'] ?? null;
277
278        $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - fetched wp result --> ' . json_encode($_POST), 'error');
279
280        // if pending payment transaction does not exist remove status condition to check if has failed transation to override it
281        if (!$paymentTransactionData && $paymentStatusName == Configure::read('worldpay.payment_status_authorised')) {
282            $paymentTransactionData = $this->PaymentTransaction->getWPPaymentTransaction2($orderCode);
283            $userId = $paymentTransactionData['user_id'] ?? null;
284        }
285
286        // return if payment transaction does not exist
287        if (!$paymentTransactionData) {
288            $msg = 'Payment transaction does not exist.';
289            $this->log(__METHOD__ . ' ' . $msg . ' kickback data -->' . $dataJson, 'wp_debug');
290            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' kickback data -->'. $dataJson, 'error');
291            // post to nc-wp-fail slack channel if payment status is equals to AUTHORISED or ERROR or REFUSED
292            if (in_array($paymentStatusName, array(Configure::read('worldpay.payment_status_authorised'), Configure::read('worldpay.payment_status_error'), Configure::read('worldpay.payment_status_refused')))) {
293                $this->slackWPErrorPostMsg($orderCode, '', $msg, $paymentStatusName);
294            }
295            // echo "[OK]"; exit;
296            return "[OK]"; 
297            // NJ-69126 I used return to force Stop Unit Test to process below and if use Exit it will stop the whole process also
298        }
299
300        if (!isset($paymentTransactionData['user_id'])) {
301            $msg = ' array key user_id does not exist.';
302            $this->log(__METHOD__ . ' ' . $msg . ' kickback data -->' . $dataJson, 'wp_debug');
303            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' kickback data -->' . $dataJson, 'error');
304            // post to nc-wp-fail slack channel if payment status is equals to AUTHORISED or ERROR or REFUSED
305            if (in_array($paymentStatusName, array(Configure::read('worldpay.payment_status_authorised'), Configure::read('worldpay.payment_status_error'), Configure::read('worldpay.payment_status_refused')))) {
306                $this->slackWPErrorPostMsg($orderCode, '', $msg, $paymentStatusName);
307            }
308            // echo "[OK]"; exit;
309            return "[OK]"; 
310            // NJ-69126 I used return to force Stop Unit Test to process below and if use Exit it will stop the whole process also
311        }
312
313        // set variables
314        $cardCompany = Configure::read('card_company.worldpay');
315        $typeId = 1; // default
316        $ptPaymentParams = json_decode($paymentTransactionData['payment_params'], true);
317        $logFileName = isset($ptPaymentParams['logFileName']) ? $ptPaymentParams['logFileName'] : 'debug';
318        $currencyCode = isset($ptPaymentParams['currencyCode']) ? $ptPaymentParams['currencyCode'] : null;
319        $formType = $ptPaymentParams['formType'];
320        $cronDateRun = isset($ptPaymentParams['cronDateRun']) ? $ptPaymentParams['cronDateRun'] : date('Y-m-d H:i:s');
321        $familyId = isset($ptPaymentParams['familyId']) ? $ptPaymentParams['familyId'] : null;
322        $userId = $familyId ? $familyId : $userId;
323        $receivablePayment = $liveLessonReceivable = $appreciationReceivable = 0;    
324
325        //remove user from currently paying users
326        UserTable::removePayingUserFromMemcache($userId);
327
328        if (!isset($ptPaymentParams['paymentAmount'])) {
329            $msg = 'Payment amount in payment transaction does not exist.';
330            $this->log(__METHOD__ . ' ' . $msg . ' kickback data -->' . $dataJson . ' - ' . json_encode($ptPaymentParams), $logFileName);
331            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' kickback data -->' . $dataJson . ' - ' . json_encode($ptPaymentParams), 'error');
332            $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
333            // echo "[OK]"; exit;
334            return "[OK]"; 
335            // NJ-69126 I used return to force Stop Unit Test to process below and if use Exit it will stop the whole process also
336        }
337
338        $amount = $ptPaymentParams['paymentAmount'];
339
340        // set user model
341        $uModel = $this->User;
342
343        // get user data
344        $userData = $uModel->find('first', array(
345            'fields' => array(
346                'status',
347                'nickname',
348                'email',
349                'hash',
350                'memo',
351                'parent_id',
352                'first_charge_date',
353                'next_charge_date',
354                'complimentary_code',
355                'payment_plan_id',
356                'monthly_speaking_attended_flg',
357                'monthly_speaking_business_attended_flg',
358                'id',
359                'hash16',
360                'currency_code',
361                'native_language2',
362                'charge_flg',
363                'fail_flg',
364                'double_check_flg',
365                'birthday',
366                'native_option',
367                'callan_option',
368                'aftee_transaction_identifier',
369                'card_token',
370                'card_company',
371                'platform',
372                'card_number',
373                'card_brand',
374                'wp_transaction_identifier'
375            ),
376            'conditions' => array('id' => $userId),
377            'recursive' => -1
378        ));
379
380        // return if user does not exist
381        if (!$userData) {
382            $this->log(__METHOD__ . ' User does not exist. payment transaction data --> ' . json_encode($paymentTransactionData) . ' | kickback data --> ' . $dataJson, $logFileName);
383            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - User does not exist. payment transaction data --> ' . json_encode($paymentTransactionData) . ' | kickback data --> ' . $dataJson, 'error');
384            // echo "[OK]"; exit;
385            return "[OK]"; 
386            // NJ-69126 I used return to force Stop Unit Test to process below and if use Exit it will stop the whole process also
387        }
388
389        // NC-9168: if card auth and user's currency does not match with processed payment currency, update to correct currency
390        if (!$userData['User']['currency_code']) {
391            if ($formType == Configure::read('payment_credit_authentication') && $currencyCode != $userData['User']['currency_code']) {
392                $uModel->validate = array();
393                $uModel->read(array('currency_code'), $userId);
394                $uModel->set(array('currency_code' => $currencyCode));
395                $uModel->save();
396                $this->log(__METHOD__ . ' Update to correct currency --> ' . $currencyCode . ' | userData -->' . json_encode($userData) . ' | kickback data --> ' . $dataJson, $logFileName);
397                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Update to correct currency --> ' . $currencyCode . ' | userData -->' . json_encode($userData) . ' | kickback data --> ' . $dataJson, 'error');
398            }
399            // NJ-69193 UNIT TETSING: Return early only during testing
400            if (getenv('UNIT_TESTING') === 'true') {
401                return;
402            }
403        }
404
405        // NC-5127: if family is withdrawn
406        if ($formType == Configure::read('payment_credit_family_monthly_payment') && $this->memcache->get('deactivated-user-'.$userId)) {
407            $this->log(__METHOD__ . ' User is withdrawn. ' . json_encode($data), 'monthly_payment');
408            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - User is withdrawn. ' . json_encode($data), 'error');
409            return ;
410        }
411
412        # NC-8194: check null payment_plan_id and price_id
413        if (
414            (!isset($ptPaymentParams['paymentPlanId']) || $ptPaymentParams['paymentPlanId'] == null) ||
415            (!isset($ptPaymentParams['priceId']) || $ptPaymentParams['priceId'] == null)
416        ) {
417            if ( $userData['User']['payment_plan_id'] && $userData['User']['price_id']) {
418                $paymentPlanId = $userData['User']['payment_plan_id'];
419                $priceId = $userData['User']['price_id'];
420            } else {
421                $defPlan = $this->PaymentPlanPrice->getDefaultPlan($userData['User']);
422                $paymentPlanId = $defPlan['paymentPlanId'];
423                $priceId = $defPlan['priceId'];
424            }
425
426            $ptPaymentParams['paymentPlanId'] = $paymentPlanId;
427            $ptPaymentParams['priceId'] = $priceId;
428
429            // NJ-69193 UNIT TETSING: Return early only during testing
430            if (getenv('UNIT_TESTING_01') === 'true') {
431                return;
432            }    
433        }
434
435        $nativeOptionPayment = 0;
436        $callanOptionPayment = 0;
437
438        // if monthly payment, retry or force charge
439        // check if user has receivable payment
440        if (in_array($formType, array(
441            Configure::read('payment_credit_monthly_payment'),
442            Configure::read('payment_credit_force_charge'),
443            Configure::read('payment_credit_retry'),
444            Configure::read('payment_credit_family_monthly_payment')
445        ))) {
446            // compute receivable payments
447            $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun);
448
449            // if has receivable payment
450            // deduct said monthly settlement from the money sent to zeus
451            if ($receivablePayment && $receivablePayment <= $amount) {
452                // deduct from monthly payment
453                $amount = $amount - $receivablePayment;
454            }
455
456            // if has native speaker payments
457            // deduct
458            if (isset($ptPaymentParams['nativeOptionPayment']) && $ptPaymentParams['nativeOptionPayment'] > 0) {
459                $nativeOptionPayment = $ptPaymentParams['nativeOptionPayment'];
460                $amount -= $nativeOptionPayment;
461            }
462
463            // if has callan option payments
464            // deduct
465            if (isset($ptPaymentParams['callanOptionPayment']) && $ptPaymentParams['callanOptionPayment'] > 0) {
466                $callanOptionPayment = $ptPaymentParams['callanOptionPayment'];
467                $amount -= $callanOptionPayment;
468            }
469
470            // compute appreciation receivable payments
471            $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.appreciation'));
472
473            // if has receivable payment
474            // deduct said monthly settlement from the money
475            if ($appreciationReceivable && $appreciationReceivable <= $amount) {
476                // deduct from monthly payment
477                $amount = $amount - $appreciationReceivable;
478            }
479
480            // compute live receivable payments
481            $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.live'));
482
483            // if has receivable payment
484            // deduct said monthly settlement from the money
485            if ($liveLessonReceivable && $liveLessonReceivable <= $amount) {
486                // deduct from monthly payment
487                $amount = $amount - $liveLessonReceivable;
488            }        
489            // NJ-69193 UNIT TETSING: Return early only during testing
490            if (getenv('UNIT_TESTING_02') === 'true') {
491                return;
492            }        
493
494        }
495
496        // Check receivables combine on `payment_credit_receivable` form type
497        if( $formType == Configure::read('payment_credit_receivable') ) {
498
499            // compute appreciation receivable payments
500            $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('appreciation_data.payment_element_type'));
501
502            // if has receivable payment
503            // deduct said monthly settlement from the money
504            if ($appreciationReceivable && $appreciationReceivable <= $amount) {
505                // deduct from monthly payment
506                $amount = $amount - $appreciationReceivable;
507            }
508
509            // compute live receivable payments
510            $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.live'));
511
512            if ($liveLessonReceivable && $liveLessonReceivable <= $amount) {
513                // deduct from monthly payment
514                $amount = $amount - $liveLessonReceivable;
515            }
516
517        }
518
519        // get receivables if form type payment credit change and amount is not equals to 0
520        if ($formType == Configure::read('payment_credit_change') && $amount > 0) {
521            // compute receivable payments
522            $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun);
523
524            // if has receivable payment
525            // deduct said monthly settlement from the money sent to zeus
526            if ($receivablePayment && $receivablePayment <= $amount) {
527                // deduct from monthly payment
528                $amount = $amount - $receivablePayment;
529            }
530
531            // compute appreciation receivable payments
532            $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.appreciation'));
533
534            // if has receivable payment
535            // deduct said monthly settlement from the money
536            if ($appreciationReceivable && $appreciationReceivable <= $amount) {
537                // deduct from monthly payment
538                $amount = $amount - $appreciationReceivable;
539            }
540
541            // compute live receivable payments
542            $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.live'));
543
544            if ($liveLessonReceivable && $liveLessonReceivable <= $amount) {
545                // deduct from monthly payment
546                $amount = $amount - $liveLessonReceivable;
547            }            
548        }
549
550        // save settlement history for tracking
551        $shData = array(
552            'userId' => $userId,
553            'params' => json_encode($data)
554        );
555
556        if (!SettlementHistoryTable::add($shData)) {
557            $msg = 'Saving user settlement history failed.';
558            $this->log(__METHOD__ . ' ' . $msg . ' data --> ' . json_encode($shData) . ' | kickback data --> ' . $dataJson, $logFileName);
559            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' data --> ' . json_encode($shData) . ' | kickback data --> ' . $dataJson, 'error');
560            $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
561            throw new InternalErrorException($msg);
562        }
563
564        $this->loadModel("ContinuationCampaign");
565        // prevent switching to replicas inside kickback
566        $this->Payment->setOverrideConnectFlg(true);
567        // if already have data stop/exit the process
568        $monthlyPaymentExist = $this->Payment->find('count', array(
569            'conditions' => array(
570                'Payment.user_id' => $userId,
571                'Payment.ordd' => $orderCode,
572                'Payment.card_company' => Configure::read('card_company.worldpay'),
573                'Payment.form_type' => $formType
574            )
575        ));
576        
577        if ($monthlyPaymentExist) {
578            $msg = ' Payments data already exist.';
579            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' --> ' . json_encode($data), 'error');
580            $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $data['PaymentStatus']);
581            // echo "[OK]"; exit;
582            return "[OK]";
583        }
584
585        switch($data['PaymentStatus']) {
586            case Configure::read('worldpay.payment_status_authorised'):
587
588                // NC-5543: return if payment method is debit and transaction identifier does not exist
589                if (!isset($data['transactionIdentifier']) && isset($data['PaymentMethod']) && in_array($data['PaymentMethod'], array('ECMC-SSL', 'MAESTRO-SSL', 'VISA-SSL'))) {
590                    $msg = 'Transaction identifier does not exist.';
591                    $this->log(__METHOD__ . ' ' . $msg . ' kickback data -->' . $dataJson, $logFileName);
592                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' kickback data -->' . $dataJson, 'error');
593                    $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
594                    // echo "[OK]"; exit;
595                    return "[OK]"; // ~ NJ-69193 I used "return" to force Stop Unit Test and to continue process below and if use Exit, it will stop the whole process also
596                }
597
598                $wpParams = array(
599                    'data' => $data,
600                    'ptData' => $paymentTransactionData,
601                    'logFileName' => $logFileName,                
602                    'amount' => $amount,
603                    'userData' => $userData,
604                    'cronDateRun' => $cronDateRun,
605                    'receivablePayment' => $receivablePayment,
606                    'appreciationReceivable' => $appreciationReceivable,
607                    'liveLessonReceivable' => $liveLessonReceivable,
608                    'transactionIdentifier' => isset($data['transactionIdentifier']) ? $data['transactionIdentifier'] : null
609                );
610
611                if( $formType == Configure::read('payment_credit_authentication') ) {
612
613                    //NJ-7548: fetch the user age $userData
614                    $uAge = UserTable::getStudentAge($userData['User']['birthday']);
615                    $uAge = $uAge ? (int) $uAge : null;
616                    $showAppreciationFlg = 0;
617
618                    //change the show appreciation flg if no birthday set or 18 and above            
619                    if (!$uAge || $uAge >= 18) {
620                        $showAppreciationFlg = 1;
621                    }
622
623                    // set user data
624                    $uModel->clear();
625                    $uModel->recursive = -1;
626                    $userSet = array( 'allow_appreciation_flg' => 1 , 'show_appreciation_flg' => $showAppreciationFlg);
627                    
628                    // set child card expiration date same as parent
629                    if (isset($ptPaymentParams['family_data']['applyPlan']['card_expiration_date'])) {
630                        $userSet['card_expiration_date'] = $ptPaymentParams['family_data']['applyPlan']['card_expiration_date'];
631                    }
632
633                    $uModel->read(array_keys($userSet), $userId);
634                    $uModel->set($userSet);
635                    $uModel->validate = array();
636                    if (!$uModel->save()) {
637                        $msg = 'Updating user failed.';
638                        $this->log(__METHOD__ . ' ' . $msg . ' data --> ' . json_encode($userSet) . ' | kickback data --> ' . $dataJson, $logFileName);
639                        $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' data --> ' . json_encode($userSet) . ' | kickback data --> ' . $dataJson, 'error');
640                        $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
641                        throw new InternalErrorException($msg);
642                    }
643
644                    if (isset($ptPaymentParams['userRegister']) && $ptPaymentParams['userRegister'] && $this->memcache->get('wp_register_completed_'.$userId)) {
645                        $msg = 'User already is enrolled Premium Plan(Free)';
646                        $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' data --> ' . json_encode($ptPaymentParams) . ' | mem data --> ' . $this->memcache->get('wp_register_completed_'.$userId) , 'error');
647                        $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
648                        return;
649                    }
650                }
651
652                // NJ-24425: release secured budget upon changing payment method FROM AFTEE to Worldpay
653                if ($formType == Configure::read('payment_credit_change')  
654                    && !empty($userData['User']['card_token']) && !empty($userData['User']['aftee_transaction_identifier'])
655                ) {
656                    // check if user is still Free (no monthly payment made yet)
657                    if ($userData['User']['payment_plan_id'] == Configure::read('payment_plans.free_trial')) {
658                        if (!class_exists('AfteePaymentService')) {
659                            App::uses('AfteePaymentService','Lib');
660                        }
661                        $afteeService = new AfteePaymentService();
662                        $checkRes = $afteeService->refund($userData, 'Change Payment Method');
663                        $this->log( '[NJ-24425] ' . json_encode($checkRes), 'aftee_debug');
664                        if ( !array_key_exists("object", $checkRes) || (isset($checkRes['object']) && $checkRes['object'] == 'error')) {
665                            $msg = '[Aftee] Failed to release secured budget';
666                            $this->log(__METHOD__ . ' ' . $msg . ' User data --> ' . json_encode($userData) . ' | refundData --> ' . json_encode($checkRes), 'aftee_debug');//AVOID [Warning] Array to string conversion
667                        }
668                    }
669                }
670                return $this->processWPPayment($wpParams);
671            case Configure::read('worldpay.payment_status_error'):
672            case Configure::read('worldpay.payment_status_refused'):
673                
674                $ptResponseText = json_decode($paymentTransactionData['response_text'], true);
675                $errorCode = isset($ptResponseText['directPayment_response']['paymentService']['reply']['orderStatus']['payment']['ISO8583ReturnCode']['@code']) ? $ptResponseText['directPayment_response']['paymentService']['reply']['orderStatus']['payment']['ISO8583ReturnCode']['@code'] : '';
676
677                // - delete token on error refused
678                if (
679                    isset($userData['User']['card_token']) &&
680                    !empty($userData['User']['card_token']) &&
681                    $errorCode == 54 // Expired Card
682                ) {
683                    $this->deleteUserToken(array(
684                        'deleteTokenParams' => array(
685                            'merchantCode' => isset($ptPaymentParams['merchantCode']) ? $ptPaymentParams['merchantCode'] : Configure::read('worldpay.merchant_code_usd'),
686                            'paymentTokenId' => $userData['User']['card_token'],
687                            'authenticatedShopperId' => $userId,
688                            'xmlName' => 'delete_token'
689                        ),
690                        'logFileName' => $logFileName,
691                        'dataJson' => $dataJson,
692                        'ptId' => $paymentTransactionData['id']
693                    ));
694
695                    // - removed user's saved card_token
696                    $uModel->clear();
697                    $uModel->recursive = -1;
698                    $uModel->read(['card_token'], $userId);
699                    $uModel->set(['card_token' => null]);
700                    $uModel->validate = array();
701                    $userSet = isset($userData) ? $userData : []; // FIX FOR Undefined variable $userSet
702                    if (!$uModel->save()) {
703                        $msg = 'Updating user card_token failed.';
704                        $this->log(__METHOD__ . ' ' . $msg . ' data --> ' . json_encode($userSet) . ' | kickback data --> ' . $dataJson, $logFileName);
705                        $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' data --> ' . json_encode($userSet) . ' | kickback data --> ' . $dataJson, 'error');
706                        $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
707                        throw new InternalErrorException($msg);
708                    }
709                }
710
711                switch ($formType) {
712                    case Configure::read('payment_credit_family_monthly_payment'):
713                    case Configure::read('payment_credit_monthly_payment'):
714                        // set user data
715                        $uModel->clear();
716                        $uModel->recursive = -1;
717                        $userSet = array(
718                            'fail_flg' => 1,
719                            'counseling_attended_flg' => 1,
720                            'charge_flg' => 0,
721                            'show_appreciation_flg' =>  0,
722                            'allow_appreciation_flg' => 0,
723                            'tip_max_amount' => null,
724                            'native_option' => 0,
725                            'callan_option' => 0,
726                            'next_charge_date' => null,
727                            'modified' => date('Y-m-d H:i:s')
728                        );
729
730                        if (isset($userData['User']['native_option']) && $userData['User']['native_option']) {
731                            $userSet['native_option_cancellation_time'] = date('Y-m-d H:i:s');
732                        }
733
734                        if (isset($userData['User']['callan_option']) && $userData['User']['callan_option']) {
735                            $userSet['callan_option_cancellation_time'] = date('Y-m-d H:i:s');
736                        }
737                        $uModel->read(array_keys($userSet), $userId);
738                        $memoStr = date('Y/m/d H:i:s')." Cancellation of Native Speaker Unlimited option";
739                        $memoStr2 = date('Y/m/d H:i:s')." Cancellation of Callan Unlimited option";
740                        $updatedMemo = $memoStr2."\n".$memoStr."\n".$userData['User']['memo'];
741                        $userSet['memo'] = $updatedMemo;
742
743                        $uModel->set($userSet);
744                        $uModel->validate = array();
745                        if (!$uModel->save()) {
746                            $msg = 'Updating user failed.';
747                            $this->log(__METHOD__ . ' ' . $msg . ' data --> ' . json_encode($userSet) . ' | kickback data --> ' . $dataJson, $logFileName);
748                            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' data --> ' . json_encode($userSet) . ' | kickback data --> ' . $dataJson, 'error');
749                            $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
750                            throw new InternalErrorException($msg);
751                        }
752
753                        $userTable = new UserTable($userData['User']);
754                        $membershipTypes = UserTable::getEngMembershipTypeData();
755                        $membershipTypeIndex = $userTable->getMembershipTypeIndex();
756                        $appreciationFlg = 0;
757                        $tipAmount = null;
758                        if (isset($ptPaymentParams['family_data']['applyPlan']['tip_max_amount']) && $ptPaymentParams['family_data']['applyPlan']['tip_max_amount']) {
759                            $tipAmount = $ptPaymentParams['family_data']['applyPlan']['tip_max_amount'];
760                        }
761                        if (isset($ptPaymentParams['family_data']['applyPlan']['allow_appreciation_flg']) && $ptPaymentParams['family_data']['applyPlan']['allow_appreciation_flg'] && $tipAmount) {
762                            $appreciationFlg = 1;
763                        }
764  
765                        $parentId = $userTable->parent_id;
766                        $is_cron = 0;
767                        if (php_sapi_name() == 'cli' || $ptPaymentParams['logFileName'] == 'monthly_payment'){
768                            $is_cron = 1;
769                        } 
770                        $currency_after = $userTable->currency_code;
771                        $plan_before = $ptPaymentParams['paymentPlanId'];
772                        $plan_after = $userTable->payment_plan_id;
773                        $usclData = array(
774                            'user_id' => $userId,
775                            'platform' => $userTable->platform ?? '',
776                            'card_company_before' => $userTable->card_company,
777                            'status_before' => $membershipTypes[$membershipTypeIndex],
778                            'status_after' => $membershipTypes[5],
779                            'controller_name' => 'payment',
780                            'action_name' => 'getWPPaymentResult',
781                            'parent_id' => $parentId,
782                            'is_cron' => $is_cron,
783                            'currency_before' => $ptPaymentParams['currencyCode'],
784                            'currency_after' => $currency_after,
785                            'payment_plan_id_before' => $plan_before,
786                            'payment_plan_id_after' => $plan_after,
787                            'default_appreciation_flg' => $appreciationFlg,
788                            'default_appreciation_amount' => $tipAmount
789                        );
790
791                        // save user change membership status
792                        if (!$this->UserStatusChangeLog->saveLog($usclData)) {
793                            $msg = 'Saving user status change log failed. - TOP';
794                            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' --> ' . json_encode($data), 'error');
795                            $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
796                            throw new InternalErrorException($msg);
797                        }
798
799                        //NJ-2814 add logs
800                        if (isset($ptPaymentParams['nativeOptionJoin']) && $ptPaymentParams['nativeOptionJoin']) {
801                            $nativeStatus = 1; // subscribed
802                            $statusBefore = $option_before_name = '';
803                        } else {
804                            $nativeStatus = 3; // unsubscribed
805                            $statusBefore = 1;
806                            $option_before_name = 'Native Unlimited Option';
807                        }
808
809                        $optionLogParams = array(
810                            'user_id' => $userId,
811                            'platform' => $ptPaymentParams['platform'],
812                            'status' => $nativeStatus,
813                            'controller_name' => $this->request->params['controller'],
814                            'action_name' => $this->request->params['action'],
815                            'user_type' => 0, // user
816                            'option_before' => $statusBefore,
817                            'option_after' => 1,
818                            'option_before_name' => $option_before_name,
819                            'option_after_name' => '',
820                            'option_type' => 1,
821                            'payment_plan_id' => $paymentPlanId
822                        );
823
824                        ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
825
826                        //NJ-2814 add logs
827                        if (isset($ptPaymentParams['callanOptionJoin']) && $ptPaymentParams['callanOptionJoin']) {
828                            $callanStatus = 1; // subscribed
829                            $statusBefore = $option_before_name = '';
830                        } else {
831                            $callanStatus = 3; // unsubscribed
832                            $statusBefore = 1;
833                            $option_before_name = 'Callan Unlimited Option';
834                        }
835
836                        $optionLogParams = array(
837                            'user_id' => $userId,
838                            'platform' => $ptPaymentParams['platform'],
839                            'status' => $callanStatus,
840                            'controller_name' => $this->request->params['controller'],
841                            'action_name' => $this->request->params['action'],
842                            'user_type' => 0, // user
843                            'option_before' => $statusBefore,
844                            'option_after' => 1,
845                            'option_before_name' => $option_before_name,
846                            'option_after_name' => '',
847                            'option_type' => 2,
848                            'payment_plan_id' => $paymentPlanId
849                        );
850
851                        ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
852
853                        // update user who join in ContinuationCampaign to fail status - 3
854                        if ($this->ContinuationCampaign->setFailedUser(array('user_id' => $userId))) {
855                            $msg = 'Failed to update ContinuationCampaign status to 3.';
856                            $this->log(__METHOD__ . ' ' . $msg . ' data --> ' . json_encode(array('user_id' => $userId)) . ' | kickback data --> ' . $dataJson, $logFileName);
857                            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' data --> ' . json_encode(array('user_id' => $userId)) . ' | kickback data --> ' . $dataJson, 'error');
858                            $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
859                            throw new InternalErrorException($msg);
860                        }
861                        
862                        // NJ-47740
863                        // confiscate pending request coupon for native and callan option
864                        $this->UsersCouponV1->confiscateOptionDiscount(array('userId' => $userId));
865
866                        // Get children list
867                        $childList = $uModel->getChildId($userId);
868
869                        // check if user is parent 
870                        if (!empty($childList)) {
871                            foreach ($childList as $childId) {
872                                // get child detail
873                                $familyMember = $uModel->find('first', array(
874                                    'fields' => array(
875                                        'User.id',
876                                        'User.memo',
877                                        'User.parent_id',
878                                        'User.native_option',
879                                        'User.callan_option'
880                                    ),
881                                    'conditions' => array('User.id' => $childId)
882                                ));
883                                $familyObj = new UserTable($familyMember['User']);
884                                $addMemo = 'Family plan[User]: family deactivation parent failed settlement';
885                                unset($familyObj->parent_id);
886
887                                // update children status to free
888                                if ($this->User->updateStatusToFree($familyObj, $addMemo)) {
889                                    // - deactivate reserved lessons of the children
890                                    $this->LessonSchedule->deactivateDisableReservedLessons($childId, true, false, true, null, false, true);
891
892                                    // NC-8645: add deactivation lock
893                                    UserTable::saveUserDeactivationLock($childId);
894
895                                    // NC-5342: add deactivation log
896                                    $this->loadModel('FamilyDeactivationLog');
897                                    $this->FamilyDeactivationLog->addLog($childId);
898                                }
899
900                                $switchAccountParams = array(
901                                    'parentId' => $userId,
902                                    'userId' => $childId
903                                );
904                                
905                                // NJ-47740
906                                // confiscate pending request coupon for native and callan option
907                                $this->UsersCouponV1->confiscateOptionDiscount(array('userId' => $childId));
908                                
909                                // delete switch account data
910                                $this->UsersFamilyAccount->removeSwitchAccount($switchAccountParams);
911                            }
912                        }
913
914                        if ($nativeOptionPayment > 0) {
915                            $nativeOptionDiscount = isset($ptPaymentParams['nativeOptionDiscount']) && $ptPaymentParams['nativeOptionDiscount'] ? $ptPaymentParams['nativeOptionDiscount'] : 0;
916                            $paymentNOData = array(
917                                'user_id' => $userId,
918                                'type_id' => $typeId,
919                                'pay_kbn' => 1,
920                                'form_type' => Configure::read('payment_native_option_monthly_payment'),
921                                'reference_id' => $userId,
922                                'amount' => $nativeOptionPayment,
923                                'ordd' => $orderCode,
924                                'card_company' => $cardCompany,
925                                'param1' => $dataJson,
926                                'param2' => 'error: wp',
927                                'transaction_code' => $orderCode,
928                                'currency_code' => $currencyCode,
929                                'payment_plan_id' => isset($ptPaymentParams['paymentPlanId']) ? $ptPaymentParams['paymentPlanId'] : null,
930                                'price_id' => isset($ptPaymentParams['priceId']) ? $ptPaymentParams['priceId'] : null,
931                                'payment_type' => isset($ptPaymentParams['paymentType']) ? $ptPaymentParams['paymentType'] : null,
932                                'discounted_amount' => $nativeOptionDiscount
933                            );
934
935                            // set payment model
936                            $pModel = $this->Payment;
937                            $pModel->clear();
938                            $pModel->create();
939                            $pModel->recursive = -1;
940                            $pModel->set($paymentNOData);
941                            $pModel->validate = array();
942
943                            if (!$pSave = $pModel->save()) {
944                                $msg = 'Saving payment failed.';
945                                $this->log(__METHOD__ . ' ' . $msg . ' data --> ' . json_encode($paymentNOData) . ' | kickback data --> ' . $dataJson, $logFileName);
946                                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' data --> ' . json_encode($paymentNOData) . ' | kickback data --> ' . $dataJson, 'error');
947                                $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
948                                throw new InternalErrorException($msg);
949                            }
950                        }
951
952                        if ($callanOptionPayment > 0) {
953                            $callanOptionDiscount = isset($ptPaymentParams['callanOptionDiscount']) && $ptPaymentParams['callanOptionDiscount'] ? $ptPaymentParams['callanOptionDiscount'] : 0;
954                            $paymentNOData = array(
955                                'user_id' => $userId,
956                                'type_id' => $typeId,
957                                'pay_kbn' => 1,
958                                'form_type' => Configure::read('payment_callan_option_monthly_payment'),
959                                'reference_id' => $userId,
960                                'amount' => $callanOptionPayment,
961                                'ordd' => $orderCode,
962                                'card_company' => $cardCompany,
963                                'param1' => $dataJson,
964                                'param2' => 'error: wp',
965                                'transaction_code' => $orderCode,
966                                'currency_code' => $currencyCode,
967                                'payment_plan_id' => isset($ptPaymentParams['paymentPlanId']) ? $ptPaymentParams['paymentPlanId'] : null,
968                                'price_id' => isset($ptPaymentParams['priceId']) ? $ptPaymentParams['priceId'] : null,
969                                'payment_type' => isset($ptPaymentParams['paymentType']) ? $ptPaymentParams['paymentType'] : null,
970                                'discounted_amount' => $callanOptionDiscount
971                            );
972
973                            // set payment model
974                            $pModel = $this->Payment;
975                            $pModel->clear();
976                            $pModel->create();
977                            $pModel->recursive = -1;
978                            $pModel->set($paymentNOData);
979                            $pModel->validate = array();
980
981                            if (!$pSave = $pModel->save()) {
982                                $msg = 'Saving payment failed.';
983                                $this->log(__METHOD__ . ' ' . $msg . ' data --> ' . json_encode($paymentNOData) . ' | kickback data --> ' . $dataJson, $logFileName);
984                                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' data --> ' . json_encode($paymentNOData) . ' | kickback data --> ' . $dataJson, 'error');
985                                $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
986                                throw new InternalErrorException($msg);
987                            }
988                        }
989                    case Configure::read('payment_credit_receivable'):
990                    case Configure::read('payment_credit_retry'):
991                    case Configure::read('payment_credit_force_charge'):
992                        // - save refuse payments
993                        $ptPaymentParams["paymentAmount"] = $amount;
994                        $data["user_id"] = $userId;
995                         $data["formType"] = $formType;
996                        if(!$this->worldpay_error_log_set($data, $ptPaymentParams)){
997                            $this->log(__METHOD__ . ' world_pay error saving payment', 'debug');
998                            $this->log(__METHOD__ . ' world_pay error saving payment', 'wp_debug');
999                            return;
1000                        }
1001                        
1002                    case Configure::read('payment_credit_authentication'):
1003                    case Configure::read('payment_credit_change'):
1004                        $ptUpdate = $this->updatePaymentTransaction(array(
1005                            'id' => $paymentTransactionData['id'],
1006                            'fields' => array(
1007                                'status' => 2, // error
1008                                'payment_id' => isset($pSave['Payment']['id']) ? $pSave['Payment']['id'] : null,
1009                                'response_text' => array('wp_kickback' => json_decode($dataJson, true))
1010                            ),
1011                            'logFileName' => $logFileName
1012                        ));
1013
1014                        if (!$ptUpdate) {
1015                            $msg = 'Updating payment transaction failed.';
1016                            $this->log(__METHOD__ . ' ' . $msg . ' data --> ' . json_encode(array('pt_id' => $paymentTransactionData['id'])) . ' | kickback data --> ' . $dataJson, $logFileName);
1017                            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' data --> ' . json_encode(array('pt_id' => $paymentTransactionData['id'])) . ' | kickback data --> ' . $dataJson, 'error');
1018                            $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
1019                            throw new InternalErrorException($msg);
1020                        }
1021                        break;
1022                }
1023                break;
1024            default:
1025                $this->log(__METHOD__ . ' No data save', $logFileName);
1026                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - No data save', 'error');
1027                break;
1028        }
1029        // echo "[OK]"; exit;
1030        return "[OK]"; // ~ NJ-69193 I used "return" to force Stop Unit Test and to continue process below and if use Exit, it will stop the whole process also
1031    }
1032
1033    //NJ-69193 ! UNIT TEST purposes private to public
1034    public function worldpay_error_log_set($data = array(), $paymentParams = array()) {
1035
1036        // set the variables
1037        $userId = isset($data['user_id']) ? $data['user_id'] : 0;
1038        $money = isset($paymentParams['paymentAmount']) ? $paymentParams['paymentAmount'] : 0;
1039        $cardCompany = Configure::read('card_company.worldpay');
1040        $formType = isset($data['formType']) ? $data['formType'] : 0;
1041        $orderCode = isset($data['OrderCode']) ? $data['OrderCode'] : null;
1042        $paymentStatusName = isset($data['PaymentStatus']) ? $data['PaymentStatus'] : '';
1043        $logFileName = isset($ptPaymentParams['logFileName']) ? $ptPaymentParams['logFileName'] : 'debug';
1044        $result = array();
1045
1046        $paymentType = isset($paymentParams['paymentType']) ? $paymentParams['paymentType'] : null;
1047        $priceId = isset($paymentParams['priceId']) ? $paymentParams['priceId'] : null;
1048        $paymentId = isset($paymentParams['paymentPlanId']) ? $paymentParams['paymentPlanId'] : null;
1049        $currencyCode = isset($paymentParams['currencyCode']) ? $paymentParams['currencyCode'] : Configure::read('currency_jpy');
1050        // $discounted_amount = isset($paymentParams['discounted_amount']) ? $paymentParams['discounted_amount'] : 0;
1051
1052        // check if has monthly discount
1053        $discounted_amount = isset($paymentParams['monthlyDiscount']) && $paymentParams['monthlyDiscount'] ? $paymentParams['monthlyDiscount'] : 0;
1054        if (!empty($paymentParams['couponUseSettlement']) && !empty($paymentParams['couponUseSettlement']['useCouponAmount']) && in_array($formType, Configure::read('allow_coupon.settlement_form_type'))) {
1055            $discounted_amount += (int)$paymentParams['couponUseSettlement']['useCouponAmount'];
1056        }
1057
1058        // Check receivable type
1059        $cronDateRun = date("Y-m-d H:i:s");
1060        $receivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun);
1061        $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('appreciation_data.payment_element_type'));
1062        $liveReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.live'));
1063
1064        try {
1065            $paymentData = array(
1066                'user_id' => $userId,
1067                'type_id' => 1,
1068                'pay_kbn' => 1,
1069                'form_type' => $formType,
1070                'reference_id' => $userId,
1071                'amount' => $money,
1072                'ordd' => $orderCode,
1073                'card_company' => $cardCompany,
1074                'param1' => json_encode($data),
1075                'param2' => 'error: wp',
1076                'transaction_code' => $orderCode,
1077                'currency_code' => $currencyCode,
1078                'payment_plan_id' => $paymentId,
1079                'price_id' => $priceId,
1080                'payment_type' => $paymentType,
1081                'discounted_amount' => $discounted_amount
1082            );
1083
1084            // set payment model
1085            $pModel = $this->Payment;
1086            $pModel->clear();
1087            $pModel->create();
1088            $pModel->recursive = -1;
1089            $pModel->set($paymentData);
1090            $pModel->validate = array();
1091            $result[$formType][] = $pModel->save();
1092
1093        } catch (\Throwable $th) {
1094            $dataJson = json_encode($data);
1095            $msg = 'Saving payment failed.';
1096            $this->log(__METHOD__ . ' ' . $msg . ' data --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, $logFileName);
1097            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' data --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, 'error');
1098            $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
1099        }
1100
1101        if (
1102            in_array($formType, array(
1103                Configure::read('payment_credit_appreciation_receivable'),
1104                Configure::read('payment_credit_receivable'),
1105                Configure::read('payment_credit_monthly_payment'),
1106                Configure::read('payment_credit_force_charge'),
1107                Configure::read('payment_credit_retry'),
1108                Configure::read('payment_credit_family_monthly_payment')
1109            )) ||
1110            (
1111                $formType == Configure::read('payment_credit_change') &&
1112                (
1113                    $receivable ||
1114                    $appreciationReceivable ||
1115                    $liveReceivable
1116                )
1117            )
1118        ) {
1119            // Appreciation 
1120            if( $appreciationReceivable > 0 ) {
1121                $this->Payment->clear();
1122                $this->Payment->create();
1123                $this->Payment->set(array(
1124                    'user_id' => $userId,
1125                    'type_id' => 1,
1126                    'pay_kbn' => 1,
1127                    'form_type' => Configure::read('payment_credit_appreciation_receivable'),
1128                    'reference_id' => $userId,
1129                    'amount' => $appreciationReceivable,
1130                    'ordd' => $orderCode,
1131                    'card_company' => $cardCompany,
1132                    'param1' => json_encode($data),
1133                    'param2' => "error: wp",
1134                    'transaction_code' => $orderCode,
1135                    'currency_code' => $currencyCode,
1136                    'price_id' => $priceId,
1137                    'payment_id' => $paymentId,
1138                    'payment_type' => $paymentType,
1139                    'discounted_amount' => $discounted_amount
1140                ));
1141                $resApp = $this->Payment->save();
1142                if (!$resApp) {
1143                    CakeLog::debug(__METHOD__ . 'Error : saving appreciation receivable -> params' . json_encode([$data, $paymentParams]));
1144                }
1145                $result[$formType][] = $resApp;
1146            }
1147
1148            // Live receivable 
1149            if( $liveReceivable > 0 ) {
1150                $this->Payment->clear();
1151                $this->Payment->create();
1152                $this->Payment->set(array(
1153                    'user_id' => $userId,
1154                    'type_id' => 1,
1155                    'pay_kbn' => 1,
1156                    'form_type' => Configure::read('payment_live_lesson_receivable'),
1157                    'reference_id' => $userId,
1158                    'amount' => $liveReceivable,
1159                    'ordd' => $orderCode,
1160                    'card_company' => $cardCompany,
1161                    'param1' => json_encode($data),
1162                    'param2' => "error: wp",
1163                    'transaction_code' => $orderCode,
1164                    'currency_code' => $currencyCode,
1165                    'price_id' => $priceId,
1166                    'payment_id' => $paymentId,
1167                    'payment_type' => $paymentType,
1168                    'discounted_amount' => $discounted_amount
1169                ));
1170                $resLive = $this->Payment->save();
1171                if (!$resLive) {
1172                    CakeLog::debug(__METHOD__ . 'Error : saving live receivable -> params' . json_encode([$data, $paymentParams]));
1173                }
1174                $result[$formType][] = $resLive;
1175            }        
1176
1177            // Reservation
1178            if( $receivable > 0 ) {
1179                $this->Payment->clear();
1180                $this->Payment->create();
1181                $this->Payment->set(array(
1182                    'user_id' => $userId,
1183                    'type_id' => 1,
1184                    'pay_kbn' => 1,
1185                    'form_type' => Configure::read('payment_credit_receivable'),
1186                    'reference_id' => $userId,
1187                    'amount' => $receivable,
1188                    'ordd' => $orderCode,
1189                    'card_company' => $cardCompany,
1190                    'param1' => json_encode($data),
1191                    'param2' => "error: wp",
1192                    'transaction_code' => $orderCode,
1193                    'currency_code' => $currencyCode,
1194                    'price_id' => $priceId,
1195                    'payment_id' => $paymentId,
1196                    'payment_type' => $paymentType,
1197                    'discounted_amount' => $discounted_amount
1198                ));
1199                $resReservation = $this->Payment->save();
1200                if (!$resReservation) {
1201                    CakeLog::debug(__METHOD__ . 'Error : saving reservation receivable -> params' . json_encode([$data, $paymentParams]));
1202                }
1203                $result[$formType][] = $resReservation;
1204            }
1205        }
1206
1207        return $result;
1208    }
1209
1210    public function complete() {
1211        $UsersCoursesData = $this->UsersCourses->findByUserId($this->Auth->user('id'));
1212        $usersCourses = isset($UsersCoursesData['UsersCourses']) ? $UsersCoursesData['UsersCourses'] : null;
1213        $courseMasterData = $this->CourseMaster->findById($usersCourses['course_id']);
1214        $courseMaster = isset($courseMasterData['CourseMaster']) ? $courseMasterData['CourseMaster'] : null;
1215        $UsersPointsData = $this->UsersPoints->findByUserId($this->Auth->user('id'));
1216        $usersPoints = isset($UsersPointsData['UsersPoints']) ? $UsersPointsData['UsersPoints'] : null;
1217        $courseMasterTable = new CourseMasterTable($courseMaster);
1218        $this->set(array(
1219            'courseMasterTable' => $courseMasterTable,
1220            'purchasePoints' => $courseMaster['add_point'],
1221            'totalPoints' => $usersPoints['point'],
1222            'purchasePointsPrice' => $courseMaster['price']
1223        ));
1224    }
1225    /**
1226     * @api {get} /payment/points/complete pointsComplete()
1227     * @apiName pointsComplete
1228     * @apiGroup Payment
1229     * @apiDescription This endpoint is used to display the points compelete page.
1230     * 
1231     * @apiSuccess {View} Render Renders the points complete page.
1232     * 
1233     * @apiError {View} Redirects back to {{ENV}}/home if the payment data is not found.
1234     * 
1235     * @apiSuccessExample Success Response:
1236     * Renders the points complete page.
1237     * 
1238     * @apiErrorExample Error Response:
1239     * Redirects back to {{ENV}}/home if the payment data is not found.
1240     * 
1241     * @apiSampleRequest off
1242     */
1243    public function pointsComplete() {
1244        $UsersPointsData = $this->UsersPoints->findByUserId($this->Auth->user('id'));
1245        $conditions = array(
1246            'user_id' => $this->Auth->user('id')
1247        );
1248        $paymentData = $this->Payment->find('first',array(
1249            'conditions' => $conditions,
1250            'order' => 'Payment.created DESC'
1251        ));
1252        if (!$paymentData) {
1253            return $this->redirect(myTools::getUrl() . '/home');
1254        }
1255
1256        $payment = $paymentData['Payment'];
1257        $usersPoints = $UsersPointsData['UsersPoints'];
1258        $courseMaster = $paymentData['CourseMaster'];
1259
1260        $this->set(array(
1261            'purchasePoints' => $courseMaster['add_point'],
1262            'totalPoints' => $usersPoints['point'],
1263            'price' => $payment['amount']
1264        ));
1265    }
1266
1267    public function callback() {
1268        $this->autoRender = false;
1269        $this->savePdataLog(2);
1270    }
1271
1272    protected function checkCallBack() {
1273        $data = $this->data;
1274
1275        if (!$this->data) {
1276            return $this->redirect(myTools::getUrl() . '/home');
1277        }
1278        if ($data['custom'] != $this->Auth->user('id')) {
1279            die('User not authorize!');
1280        }
1281        $courseMasterData = $this->CourseMaster->findById($data['item_number1']);
1282        if (!isset($courseMasterData)) {
1283            die('Invalid Course ID');
1284        }
1285        $courseMaster = $courseMasterData['CourseMaster'];
1286        if ($courseMaster['price'] > $data['mc_gross']) {
1287            die('Invalid amount');
1288        }
1289        if ($data['payment_status'] != 'Completed') {
1290            die('Payment not yet completed');
1291        }
1292        return $data;
1293    }
1294
1295    /*
1296    1 = return transfer data
1297    2 = IPN or Instant payment notification
1298    */
1299    protected function savePdataLog() {
1300        if ($_REQUEST) {
1301            $data = $_REQUEST;
1302            $data['referer'] = $_SERVER['HTTP_REFERER'];
1303            $data['ip'] = $_SERVER['REMOTE_ADDR'];
1304            $this->data = $data;
1305        }
1306    }
1307
1308
1309
1310    /**
1311     * 以下 テレコム決済周り
1312     **/
1313
1314    public function t_start() {
1315
1316        $userData = $this->User->findById($this->Auth->user('id'));
1317        if (!$userData) {
1318            return $this->redirect(myTools::getUrl() . '/');
1319        }
1320        $user = new UserTable($userData['User']);
1321
1322
1323        // 既に有料会員の場合
1324        if ($user->charge_flg) {
1325            return $this->redirect(myTools::getUrl() . '/');
1326        }
1327
1328        // 既に登録済みの場合(念のため)
1329        $data = $this->PaymentTransaction->findByPaymentHashAndStatusAndUserId($this->Auth->user('hash16'), 1, $this->Auth->user('id'));
1330        if ($data) {
1331            return $this->redirect(myTools::getUrl() . '/');
1332        }
1333
1334        // テレコム遷移用データ
1335        App::uses('telecomcheckout','Vendor');
1336        $telecom = new telecomcheckout();
1337
1338        // 固定
1339        $courseId = Configure::read("credit.course_id");
1340
1341        // set the default password
1342        $password = myTools::generateRandomStr(8);
1343
1344        // set course param
1345        $course = new stdClass();
1346
1347
1348        // create payment transaction
1349        $this->PaymentTransaction->create();
1350        $this->PaymentTransaction->set(array(
1351            'user_id' => $this->Auth->user('id'),
1352            'payment_hash' => $user->hash16,
1353            'status' => 0,
1354            'course_id' => $courseId,
1355            'password' => $password,
1356        ));
1357        $this->PaymentTransaction->save();
1358
1359
1360        // 事前登録会員と通常会員でIDを分ける
1361        #$course->rebill_param_id = ($user->member_kbn==1) ? '1month3900yen_2' : '1month3900yen';
1362
1363#        $course->rebill_param_id = '1month3900yen_3';
1364
1365        // NC-213で更新
1366#        $course->rebill_param_id = '1month3900yen';
1367
1368        // NC-416で更新
1369        $course->rebill_param_id = Configure::read("credit.rebill_param_id");
1370
1371        // set to telecom parameters
1372        $telecom->setParams(array(
1373            'sendid'            => $user->hash16,
1374            'usrmail'           => $user->email,
1375            'redirect_url'      => '',
1376            'redirect_back_url' => '',
1377            'rebill_param_id'   => $course->rebill_param_id,
1378            'option'            => $courseId,
1379            'sendpass'          => $password,
1380        ));
1381        // fetch telecom parameters
1382        $params = $telecom->getParams();
1383        $url = $telecom->auth_url . '?';
1384        foreach ($params as $key => $val) {
1385            $url .= $key . '=' . $val . '&';
1386        }
1387        return $this->redirect($url);
1388    }
1389
1390    public function charge_company_select(){
1391
1392    }
1393
1394    /**
1395     * @api {post} /payment/z_start/:data/:formType/:referrer z_start()
1396     * @apiName z_start
1397     * @apiGroup Payment
1398     * @apiDescription This endpoint is used to start the payment process in zeus.
1399     * 
1400     * @apiParam {Object} data The payment data.
1401     * @apiParam {String} [data.ZPaymentFullLogs.clientip] The client's IP address.
1402     * @apiParam {Number} [data.ZPaymentFullLogs.cardnumber] The card number.
1403     * @apiParam {Number} [data.ZPaymentFullLogs.expyy] The card's expiration year.
1404     * @apiParam {Number} [data.ZPaymentFullLogs.expmm] The card's expiration month.
1405     * @apiParam {Number} [data.ZPaymentFullLogs.telno] The telephone number.
1406     * @apiParam {String} [data.ZPaymentFullLogs.username] The username.
1407      * @apiParam {String} [data.ZPaymentFullLogs.paymentHash] The payment hash.
1408     * @apiParam {Number} [data.ZPaymentFullLogs.discounted_amount] The discounted amount.
1409     * @apiParam {String} [data.ZPaymentFullLogs.zeusTokenValue] The Zeus token value.
1410     * @apiParam {String} [data.zeus_card_option] The Zeus card option.
1411     * @apiParam {String} [data.origin_redirect] The origin redirect URL.
1412     * @apiParam {String} formType The form type.
1413     * @apiParam {String} referrer The referrer url.
1414     * 
1415     * @apiSuccess (View) Redirect /payment/payment_credit_register_complete Redirects to payment credit register complete.
1416     * @apiSuccess (View) Redirect /payment/payment_credit_charge_complete Redirects to payment credit charge complete.
1417     * @apiSuccess (View) Redirect /payment/coupon_payment_credit_charge_complete Redirects to coupon payment credit charge complete.
1418      * @apiSuccess (View) Redirect /payment/payment_credit_change_complete Redirects to payment credit change complete.
1419     * @apiSuccess (View) Redirect /store/card_register_complete Redirects to card register complete.
1420     * @apiSuccess (View) Redirect /payment/payment_credit_retry_complete Redirects to payment credit retry complete.
1421     * @apiSuccess (View) Redirect /StudyAbroad/payment_complete Redirects to study abroad payment complete.
1422     * 
1423     * @apiError (View) Redirect / Redirects to home page.
1424     * 
1425     * @apiSuccessExample Success Response payment credit authentication:
1426     * Redirects to {{ENV}}//payment/payment_credit_register_complete
1427     * 
1428     * @apiSUccessExample Success Response payment_credit_force_charge:
1429     * Redirects to {{ENV}}/payment/payment_credit_charge_complete
1430     * 
1431     * @apiSuccessExample Success Response payment_credit_force_charge with complimentary user:
1432     * Redirects to {{ENV}}/payment/coupon_payment_credit_charge_complete
1433     * 
1434     * @apiSuccessExample Success Response payment_credit_change:
1435     * Redirects to {{ENV}}/payment/payment_credit_change_complete
1436     * 
1437     * @apiSuccessExample Success Response payment_credit_change & origin is store:
1438     * Redirects to {{ENV}}/store/card_register_complete
1439     * 
1440     * @apiSuccessExample Success Response payment_credit_retry:
1441     * Redirects to {{ENV}}/payment/payment_credit_retry_complete
1442     * 
1443     * @apiSuccessExample Success Response payment_study_abroad:
1444     * Redirects to {{ENV}}/StudyAbroad/payment_complete
1445     * 
1446     * @apiErrorExample Error Response:
1447     * Redirects to {{ENV}}/
1448     * 
1449     * @apiSampleRequest off
1450     */
1451    public function z_start($data = null, $formType = null, $referrer = null){
1452        $this->autoRender = false;
1453        if (!$userData = $this->sharedUserData['User']) {
1454            return $this->redirect(myTools::getUrl() . '/');
1455        }
1456        $user = new UserTable($this->sharedUserData['User']); //NJ-69193 ~ Fix the error in $user below
1457        $modelname ="ZPaymentFullLogs";
1458        $this->set(compact("modelname"));
1459
1460        if ($data) {
1461            switch ($formType) {
1462                case Configure::read('payment_credit_retry'):
1463                    // NJ-47740 - get monthly reqeust coupon discount
1464                    $coupon = $this->UsersCouponV1->getCouponUseRequest(array(
1465                        'userId' => $userData['id'],
1466                        'kbn' => Configure::read('coupon_kbn.monthly_settlement')
1467                    ));
1468
1469                    if (!empty($coupon['amount']) && !empty($coupon['grp_id'])) {
1470                        $discountedCoupon = $coupon['amount'];
1471                        
1472                        if ($discountedCoupon >= $data[$modelname]['money']) {
1473                            $data[$modelname]['discounted_amount'] = $data[$modelname]['money'];
1474                            $data[$modelname]['money'] = 0;
1475                        } else {
1476                            $discountedAmount = $discountedCoupon ? $discountedCoupon : 0;
1477                            $data[$modelname]['money'] -= $discountedAmount;
1478                        }
1479                    }
1480                case Configure::read('payment_credit_force_charge'):
1481                case Configure::read('payment_individual_corporate_standard'):
1482                case Configure::read('payment_individual_corporate_premium'):
1483                case Configure::read('payment_lite_credit_paid'):
1484                case Configure::read('payment_credit_change'):
1485                case Configure::read('payment_credit_chocotto_monthly_payment'):
1486                case Configure::read('payment_credit_chocotto_force_charge'):
1487                    $annualDiscountOptionData = [];
1488                    $annualDiscountOptionAmount = 0;
1489                    if ($formType == Configure::read('payment_credit_retry')) {
1490                        // get user active annual discount option
1491                        $annualDiscountOptionData = $this->UserDiscountOptionsTerm->getTerm([
1492                            'user_id' => $userData['id'],
1493                            'discount_option_id' => Configure::read('discount_option.annual.plan_id'),
1494                            'status' => 1
1495                        ]);
1496                    } elseif ($formType == Configure::read('payment_credit_force_charge')) {
1497                        $annualDiscountOptionData = $this->DiscountOptionsPrice->getPaymentData([
1498                            'currencyCode' => $userData['currency_code'],
1499                            'discountOptionId' => Configure::read('discount_option.annual.plan_id')
1500                        ]);
1501                    }
1502
1503                    if ($annualDiscountOptionData) {
1504                        $annualDiscountOptionAmount = $annualDiscountOptionData['amount'];
1505                    }
1506
1507                    // - check if not annual discount option
1508                    if(isset($data[$modelname]['payment_plan_type']) && $data[$modelname]['payment_plan_type'] == 0) {
1509                        $annualDiscountOptionAmount = 0;
1510                    }
1511
1512                    // get reserve payment receivable
1513                    $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userData['id']);
1514
1515                    // get appreciation payment receivable
1516                    $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userData['id'], false, Configure::read('appreciation_data.payment_element_type'));
1517
1518                    // get live lesson payment receivable
1519                    $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userData['id'], false, Configure::read('payment_element_type.live'));
1520
1521                    $money = $data[$modelname]['money'] + $receivablePayment + $appreciationReceivable + $liveLessonReceivable;
1522                    $money -= $annualDiscountOptionAmount;
1523
1524                    break;
1525                case Configure::read('payment_prepaid_corporate_light_member'):
1526                case Configure::read('payment_study_abroad'):
1527                    $money = $data[$modelname]['money'];
1528                    break;
1529                case Configure::read('payment_credit_authentication'):
1530                case Configure::read('payment_lite_credit_free'):
1531                case Configure::read('payment_credit_chocotto_free'):                
1532                    $money = 0;
1533                    break;
1534                default:
1535                    $money = 0;
1536                    $formType = Configure::read('payment_credit_default');
1537                    break;
1538            }
1539
1540            $pData = array(
1541                'clientIp' => (int) $data[$modelname]['clientip'],
1542                'cardNumber' => $data[$modelname]['cardnumber'],
1543                'expyy' => isset($data[$modelname]['expyy']) ? (int) $data[$modelname]['expyy'] : 0,
1544                'expmm' => isset($data[$modelname]['expmm']) ? (int) $data[$modelname]['expmm'] : 0,
1545                'telNo' => (int) $data[$modelname]['telno'],
1546                'email' => $userData['email'],
1547                'username' => $data[$modelname]['username'],
1548                'sendId' => (int) $userData['id'],
1549                'money' => $money,
1550                'tokenKey' => isset($data[$modelname]['zeusTokenValue']) ? $data[$modelname]['zeusTokenValue'] : null,
1551                'paymentHash' => $data[$modelname]['paymentHash']
1552            );
1553
1554            // send curl request
1555            if (isset($data['zeus_card_option']) && $data['zeus_card_option'] == "prev") {
1556                $res = ZChargeComponent::charge_with_regsterd_card(json_encode($pData));
1557            } else {
1558
1559                // update payment params -  add card expiration date
1560                if (isset($data[$modelname]['expyy']) && isset($data[$modelname]['expmm'])) {
1561                    $paymentParamsData = array('cardExpirationDate' => date('Y-m-t', strtotime($data[$modelname]['expyy'] . '-' . $data[$modelname]['expmm'])));
1562                    $this->PaymentTransaction->updatePaymentParams(array('paymentHash' => $data[$modelname]['paymentHash'], 'updateData' => $paymentParamsData));
1563                }
1564
1565                // get zeus challenge flag
1566                $zeus3DSecureChallengeFlg = $this->memcache->get('zeus3DSecureChallengeFlg_' . $userData['id']);
1567                
1568                // NJ-25522: payment was charged after challenge already
1569                if ($zeus3DSecureChallengeFlg) {
1570                    $zeus3DSecurePaymentSuccessFlg = $this->memcache->get('zeus3DSecurePaymentSuccessFlg_' . $userData['id']);
1571                    $res = !empty($zeus3DSecurePaymentSuccessFlg) && $zeus3DSecurePaymentSuccessFlg == 'OK' ? 'Success_order' : 'failure_order';
1572
1573                    // clear flag
1574                    $this->memcache->delete('zeus3DSecureChallengeFlg_' . $userData['id']);
1575                    $this->memcache->delete('zeus3DSecurePaymentSuccessFlg_' . $userData['id']);
1576
1577                // default process without challenge, charge directly
1578                } else {
1579                    $res = $this->ZCharge->charge_regist(json_encode($pData));
1580
1581                }
1582            }
1583
1584            // if successful
1585            if (isset($res) && ($res[0] == "Success_order" || $res == "Success_order")) {
1586                $re_campaign = $this->UserWithdrawReenrollCampaign->find('first', array(
1587                    'conditions' => array(
1588                        'user_id' => $this->Auth->user("id")
1589                    ),
1590                    'fields' => array('id', 'status')
1591                ));
1592                if (
1593                    isset($re_campaign['UserWithdrawReenrollCampaign']['status']) && 
1594                    $re_campaign['UserWithdrawReenrollCampaign']['status'] == 0 &&
1595                    $user->currency_code == Configure::read('currency_jpy')
1596                ) {
1597                    // give 500 points
1598                    $pointParams = array(
1599                        'userId' => $user->id,
1600                        'point' => 500, // re-register campaign points
1601                        'kbn' => Configure::read("point_history.bonus"),
1602                        'kbnType' => 1, // add coin
1603                        'coinType' => 2, // service coin
1604                        'coinFailMessage' => Configure::read('coin.failed.buy_coin')
1605                    );
1606                    ClassRegistry::init('UsersPoint')->performPointTransaction($pointParams);
1607
1608                    // update re-enroll campaign status
1609                    $update_reenroll_campaign = array(
1610                        'id' => $re_campaign['UserWithdrawReenrollCampaign']['id'],
1611                        'status' => 1,
1612                    );
1613                    $this->UserWithdrawReenrollCampaign->clear();
1614                    $this->UserWithdrawReenrollCampaign->read(array_keys($update_reenroll_campaign),$update_reenroll_campaign['id']);
1615                    $this->UserWithdrawReenrollCampaign->set($update_reenroll_campaign);
1616                    $this->UserWithdrawReenrollCampaign->save();
1617
1618                }
1619                
1620                if (
1621                    $formType == Configure::read('payment_credit_authentication') || 
1622                    $formType == Configure::read('payment_lite_credit_free') ||
1623                    $formType == Configure::read('payment_credit_chocotto_free')
1624                ) {
1625                    $this->Session->delete('PaymentCreditRegisterInfo');
1626                    // send registration completion email
1627                    App::uses('myMailer','Lib');
1628                    $mail_id = Configure::read('site_in_mail.student_registration_complete');
1629                    if ($userData &&  !in_array($userData['currency_code'], Configure::read('global_free_trail_currencies') ) ) {
1630                        $mail_id = Configure::read('site_in_mail.registration_no_trial_currencies');
1631                    }
1632                    myMailer::sendTemplateMail($mail_id, $userData['email'], $userData, array(), 'User');
1633                    //NJ-13482
1634                    $this->Session->write('payment_credit_register_complete', true);
1635                    return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_register_complete'));
1636                } else if (
1637                    $formType == Configure::read('payment_credit_force_charge') ||
1638                    $formType == Configure::read('payment_lite_credit_paid') ||
1639                    $formType == Configure::read('payment_credit_chocotto_monthly_payment')
1640                ) {
1641                    $this->Session->delete('PaymentCreditChargeInfo');
1642                    $action = 'payment_credit_charge_complete';
1643                    // if complimentary plan user before
1644                    if ($this->memcache->get('com_plan_user_'.$userData['id'])) {
1645                        $this->memcache->delete('com_plan_user_'.$userData['id']);
1646                        $action = 'coupon_payment_credit_charge_complete';
1647                    }
1648
1649                    // Teacher Perks : Student re-enroll
1650                    if ( $formType == Configure::read('payment_credit_force_charge')) {
1651                        ClassRegistry::init('TeacherPerksAccount')->reEnroll(['user_id' => $userData['id']]);
1652                    }
1653                    
1654                    //    NC-7644 Add code reward for re-enroolling with the campaign code
1655                    $this->log(__METHOD__ ."sai_debug -> Add 500 Coin Reward for re-enroll: ", "debug");
1656                    $this->addCoinRewardForReenroll($userData);
1657
1658                    // - add monthly mc coin if lite plan user 
1659                    if ($formType == Configure::read('payment_lite_credit_paid')) {
1660                        $this->liteUserAddCoinRewardForReenroll(array('id' => $userData['id']));
1661                    }
1662                    
1663                    return $this->redirect(array('controller' => 'payment', 'action' => $action));
1664                } else if ($formType == Configure::read('payment_credit_change')) {
1665                    if (isset($data["origin_redirect"]) ) {
1666                        return $this->redirect(array('controller' => 'store', 'action' => 'card_register_complete','?' => $data["origin_redirect"] ));
1667                    } else{
1668                        return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_change_complete'));
1669                    }
1670                } else if ($formType == Configure::read('payment_credit_retry')) {
1671                    // - flag manual paying user success
1672                    UserTable::saveManualPayingUsersToMemcache($userData['id']);
1673                    $this->Session->delete('PaymentCreditRetryInfo');
1674                    $this->Session->delete('PaymentCreditRetryInfoCorporateAmount');
1675                    return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_retry_complete'));
1676                } elseif (
1677                    $formType == Configure::read('payment_individual_corporate_standard') ||
1678                    $formType == Configure::read('payment_individual_corporate_premium') ||
1679                    $formType == Configure::read('payment_prepaid_corporate_light_member')
1680                ) {
1681                    $this->Session->delete('PaymentCreditChargeInfo');
1682                    $this->Session->delete('PaymentCreditChargeCorporateData');
1683                    // NJ-28462 [PC][Dev] Organize the re-enrollment behavior after corporate plan ends From bug ticket (NJ-28435)  
1684                    $this->Session->delete('corporateIndiPrices');
1685                    
1686
1687                    return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_charge_complete'));
1688                } else if ($formType == Configure::read('payment_study_abroad')) { 
1689                    
1690                    return $this->redirect(array('controller' => 'StudyAbroad', 'action' => 'payment_complete'));
1691                } else {
1692                    return $this->redirect(myTools::getUrl() . '/');
1693                }
1694            } else {
1695                // NC-3914: check if user is using new card
1696                // store to session
1697                if (
1698                    (isset($referrer) && $referrer['action'] == 'payment_credit_change') ||
1699                    (isset($data[$modelname]['zeus_card_option']) && $data[$modelname]['zeus_card_option'] == 'new')
1700                ) {
1701                    $this->Session->write('user_new_card_info', $data);
1702                }
1703                // handle errors
1704                $this->handleCreditResponseError($res, $referrer);
1705            }
1706        }
1707    }
1708
1709    /**
1710     * @api {get} /:language/payment/payment_credit_register_complete payment_credit_register_complete()
1711     * @apiName payment_credit_register_complete
1712     * @apiGroup Payment
1713     * @apiDescription This endpoint is used to redirect to the notice to user page after payment credit register complete.
1714     * 
1715     * @apiParam {String} language Language code of the user.
1716     * 
1717     * @apiSuccess {View} Redirect Redirects to {{ENV}}/account/notice_to_user.
1718     * @apiSuccess {View} Redirect Redirects to {{ENV}}/choco_camp_success if the user is in chocotto plan.
1719     * 
1720     * @apiSuccessExample Success Response:
1721     * Redirects to {{ENV}}/account/notice_to_user.
1722     * 
1723     * @apiSuccessExample Success Response Chocotto Plan:
1724     * Redirects to {{ENV}}/choco_camp_success if the user is in chocotto plan.
1725     * 
1726     * @apiSampleRequest off
1727     */
1728    public function payment_credit_register_complete() {
1729        $memKey = "pc_wp_register_card_type_{$this->sharedUserData['User']['api_token']}";
1730        $counselingModalMemKey = 'counseling_modal_flg'.$this->Auth->user('id');
1731
1732        // delete if memcache exist
1733        if ($this->memcache->get($memKey)) {
1734            $this->memcache->delete($memKey);
1735        }
1736
1737        if ($this->memcache->get($counselingModalMemKey)) {
1738            $this->memcache->delete($counselingModalMemKey);
1739        }
1740
1741        $userId = $this->Auth->user('id');
1742        $coinData = array(
1743            "status" => false,
1744            "ref" => $userId
1745        );
1746        $this->Session->write("coinReadRefStatus", $coinData);
1747
1748        //NJ-13482
1749        $this->Session->write('reenroll_native_option', true);
1750
1751        //- NJ-27262 chocotto plans redirect
1752        if (in_array($this->sharedUserData['User']['payment_plan_id'], [
1753            Configure::read('payment_plans.free_trial_chocotto'),
1754            Configure::read('payment_plans.chocotto_plan')
1755        ])) {
1756            return $this->redirect('/chocotto_camp_success');
1757        }
1758        return $this->redirect(array('controller' => 'account', 'action' => 'notice_to_user'));
1759    }
1760    /**
1761     * @api {get} /:language/payment/coupon_payment_credit_charge_complete coupon_payment_credit_charge_complete()
1762     * @apiName coupon_payment_credit_charge_complete
1763     * @apiGroup Payment
1764     * @apiDescription This endpoint is used to redirect payment credit charge complete page after using coupon.
1765     * 
1766     * @apiParam {String} language Language code of the user.
1767     * 
1768     * @apiSuccess {View} Render Renders the payment credit charge complete page.
1769     * 
1770     * @apiSuccessExample Success Response:
1771     * Renders the payment credit charge complete page.
1772     * 
1773     * @apiSampleRequest off
1774     */
1775    public function coupon_payment_credit_charge_complete() {
1776        $this->set('comPlanBefore', true);
1777        $this->payment_credit_charge_complete();
1778    }
1779
1780    /**
1781     * @api {get} /:language/payment/payment_credit_charge_complete payment_credit_charge_complete()
1782     * @apiName payment_credit_charge_complete
1783     * @apiGroup Payment
1784     * @apiDescription This endpoint is used to display the credit card charge complete page.
1785     * 
1786     * @apiParam {String} language Language code of the user.
1787     * 
1788     * @apiSuccess {View} Render Renders the credit card charge complete page.
1789     * @apiSuccess {View} Render Renders the mobile credit card charge complete page if the user is using mobile.
1790     * @apiSuccess {View} Redirect Redirects to {{ENV}}/register/chocotto_camp_success if the user is in chocotto plan.
1791     * 
1792     * @apiError {View} Redirect Redirects to {{ENV}}//account
1793     * 
1794     * @apiSuccessExample Success Response PC:
1795     * Renders the credit card charge complete page.
1796     * 
1797     * @apiSuccessExample Success Response Mobile:
1798     * Renders the mobile credit card charge complete page.
1799     * 
1800     * @apiSuccessExample Success Response Chocotto Plan:
1801     * Redirects to {{ENV}}/register/chocotto_camp_success if the user is in chocotto plan.
1802     * 
1803     * @apiErrorExample Error Response:
1804     * Redirects to {{ENV}}//account
1805     * 
1806     * @apiSampleRequest off
1807     */
1808    public function payment_credit_charge_complete(){
1809        $this->set('title_for_layout', '登録完了|オンライン英会話のネイティブキャンプ');
1810        $user = $this->sharedUserData['User'];
1811
1812        $memKey = "pc_wp_charge_card_type_{$user['api_token']}";
1813        // delete memcache
1814        if ($this->memcache->get($memKey)) {
1815            $this->memcache->delete($memKey);
1816        }
1817
1818        if ($this->Session->read('complimentaryToPlan')) {
1819            $this->Session->delete('complimentaryToPlan');
1820        }
1821
1822        $this->set('nickname', $user['nickname']);
1823        if ($this->RequestHandler->isMobile()) {
1824            $this->layout = ('mobile');
1825            $this->render('/Mobile/Reregister/payment_credit_charge_complete');
1826        } else {
1827            $this->render('/Payment/payment_credit_charge_complete');
1828        }
1829
1830        $userId = $user['id'] ?? "";
1831
1832        // NJ-33414 Update Lesson Request to Default
1833        $this->UsersDetail->openDBReplica();
1834        $usersDetail = $this->UsersDetail->find('first', array(
1835            'fields' => array('lesson_request_flg'),
1836            'conditions' => array('UsersDetail.user_id' => $userId),
1837            'recursive' => -1
1838        ));
1839        $this->UsersDetail->closeDBReplica();
1840
1841        if( $usersDetail ) {
1842            $this->UsersDetail->clear();
1843            $this->UsersDetail->query("
1844                    UPDATE
1845                        `english`.`users_detail`
1846                    SET
1847                        lesson_request_flg = 1
1848                    WHERE
1849                        user_id = {$user['id']}
1850            ");
1851
1852            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - update user_detail lesson_request_flg to 1', 'error');
1853        } else {
1854            $this->UsersDetail->clear();
1855            $this->UsersDetail->set([
1856                'user_id' => $user['id'],
1857                'individual_card_fail_flg'    => 0,
1858                'lesson_request_flg' => 1
1859            ]);
1860            $this->UsersDetail->validate = [];
1861            $this->UsersDetail->save();
1862
1863            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - add user detail with individual_card_fail_flg to 0 and lesson_request_flg to 1', 'error');
1864        }
1865
1866        // NJ-23812 : redirect to url if url is from /account re-register
1867        $sessionParams = array(
1868            'result' => true,
1869            'auth_bonus_coin' => 0,
1870            'is_register_card' => false
1871        );
1872
1873        // NJ-23812: update user payment plan data ?
1874        $userData = $this->User->find('first', array(
1875            'fields' => array(
1876                'id',
1877                'payment_plan_id',
1878                'corporate_type',
1879            ),
1880            'conditions' => array('id' => $user['id']),
1881            'recursive' => -1
1882        ));
1883
1884        if ($userData) {
1885            $corpType = myTools::getCoporateTypeUsingPaymentPlanId($userData['User']['payment_plan_id']);
1886            $this->sharedUserData['User']['payment_plan_id'] = $userData['User']['payment_plan_id'];
1887            $this->sharedUserData['User']['corporate_type'] = $corpType;
1888        }
1889
1890        // NJ-23812 : skip  show welcome back modal
1891        $this->Session->write('show_welcome_back_modal',$sessionParams);
1892
1893        //-chocotto plan logout user
1894        if ($userData['User']['payment_plan_id'] == Configure::read('payment_plans.chocotto_plan')) {
1895            $this->Auth->logout();
1896            return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/register/chocotto_camp_success");
1897        }
1898        return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/account");
1899    }
1900
1901    /**
1902     * @api {get} /:language/payment/payment_credit_retry_complete payment_credit_retry_complete()
1903     * @apiName payment_credit_retry_complete
1904     * @apiGroup Payment
1905     * @apiDescription This endpoint is used to redirect to account after payment credit retry complete.
1906     * 
1907     * @apiParam {String} language Language code of the user.
1908     * 
1909     * @apiSuccess {View} Redirect Redirects to {{ENV}}/account.
1910     * 
1911     * @apiSuccessExample Success Response:
1912     * Redirects to {{ENV}}/account.
1913     * 
1914     * @apiSampleRequest off
1915     */
1916    public function payment_credit_retry_complete(){
1917        $user = $this->sharedUserData['User'];
1918        $this->set('nickname', $user['nickname']);
1919
1920        // ~ process child receivable
1921        $childsDetail = $this->User->getChildsDetail($user['id']);
1922
1923        if (!empty($childsDetail)) {
1924            foreach ($childsDetail as $detail) {
1925                $this->processChildReceivablePayment($detail['User'], $user);
1926            }
1927        }
1928
1929        $memKey = "pc_wp_retry_card_type_{$user['api_token']}";
1930        // delete memcache
1931        if ($this->memcache->get($memKey)) {
1932            $this->memcache->delete($memKey);
1933        }
1934
1935        // NJ-23812 : redirect to url if url is from /account re-register
1936            $sessionParams = array(
1937                'result' => true,
1938                'auth_bonus_coin' => 0,
1939                'is_register_card' => false
1940            );
1941
1942            // NJ-23812 : skip  show welcome back modal
1943            $this->Session->write('show_welcome_back_modal',$sessionParams);
1944            return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/account");
1945    }
1946
1947    /**
1948     * @api {get} /:language/payment/payment_credit_change_complete payment_credit_change_complete()
1949     * @apiName payment_credit_change_complete
1950     * @apiGroup Payment
1951     * @apiDescription This endpoint is used to display the credit card change complete page.
1952     * 
1953     * @apiParam {String} language Language code of the user.
1954     * 
1955     * @apiBody {String} page_origin The page origin of the request.
1956     * 
1957     * @apiSuccess {View} Render Renders the credit card change complete page.
1958     * 
1959     * @apiError {View} Redirect Redirects to {{ENV}}/account if the page origin is not found.
1960     * 
1961     * @apiExample Example usage:
1962     * {
1963     *         "page_origin": "account"
1964     * }
1965     * 
1966     * @apiSuccessExample Success Response:
1967     * Renders the credit card change complete page.
1968     * 
1969     * @apiErrorExample Error Response:
1970     * Redirects to {{ENV}}/account if the page origin is not found.
1971     * 
1972     * @apiSampleRequest off
1973     */
1974    public function payment_credit_change_complete(){
1975        $memKey = "pc_wp_change_{$this->sharedUserData['User']['api_token']}";
1976        // delete memcache
1977        if ($this->memcache->get($memKey)) {
1978            $this->memcache->delete($memKey);
1979        }
1980
1981        $url = "/account";
1982        $platform = "pc";
1983        $requestData = $this->request->query;
1984
1985        if ( isset($requestData['page_origin']) ) {
1986            $useUrlArr = Configure::read('change_credit_card_redirect.url');
1987            if ( isset($useUrlArr[$platform][$requestData['page_origin']]) ) {
1988                $url = $useUrlArr[$platform][$requestData['page_origin']];
1989            }
1990        }
1991
1992        // NJ-23812 : redirect to url if url is from /account re-register
1993        if ($url == "/account") {
1994            return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/account");
1995        }
1996
1997
1998        $this->set('url', $url );
1999        $this->set('title_for_layout', 'クレジット情報変更完了|オンライン英会話のネイティブキャンプ');
2000    }
2001
2002    /**
2003     * @api {get} /payment/handleCreditResponseError/:res/:referrer
2004     * @apiName handleCreditResponseError
2005     * @apiGroup Payment
2006     * @Description This endpoint is used to point out errors and returns it from the referrer url.
2007     * 
2008     * @apiParam {String} res The response from the credit card charge.
2009     * @apiParam {String} referrer The referrer url
2010     * 
2011     * @apiSuccess {String} error The error message
2012     * @apiSuccess {View} Redirect Redirects to the referrer url / home page if referrer url is not found
2013     * 
2014     * @apiSuccessExample Success Response Settlement Failure:
2015     * Error : 決済失敗
2016     * Redirects to the referrer url or home page
2017     * 
2018     * @apiSuccessExample Success Response Under Maintenance:
2019     * Error : メンテナンス中
2020     * Redirects to the referrer url or home page
2021     * 
2022     * @apiSuccessExample Success Response Connect Error:
2023     * Error : Connect Error
2024     * Redirects to the referrer url or home page
2025     * 
2026     * @apiSuccessExample Success Response Invalid Card Number:
2027     * Error : カード番号が正しくありません 半角数字で入力してください。ハイフン(-)は必要ありません。
2028     * Redirects to the referrer url or home page
2029     * 
2030     * @apiSuccessExample Success Response Invalid Telephone Number:
2031     * Error : 電話番号が正しくありません 半角数字で入力してください。ハイフン(-)は必要ありません。
2032     * Redirects to the referrer url or home page
2033     * 
2034     * @apiSuccessExample Success Response Invalid Username:
2035     * Error : クレジットカードに記載されている名前を半角英字で入力してください。
2036     * Redirects to the referrer url or home page
2037     * 
2038     * @apiSuccessExample Success Response Invalid Client IP:
2039     * Error : 決済失敗
2040     * Redirects to the referrer url or home page
2041     * 
2042     * @apiSuccessExample Success Response Other Errors:
2043     * Error : $res
2044     * Redirects to the referrer url or home page
2045     * 
2046     * @apiSampleRequest off
2047     */
2048    public function handleCreditResponseError($res, $referrer){
2049        // errors
2050        $error = "";
2051        $failureOrder = "failure_order";
2052        $maintenance = "maintenance";
2053        $connectError = "connect error";
2054        $cardNumberError = "Invalid Cardnumber";
2055        $telnoError = "Invalid telno";
2056        $usernameError = "Invalid username";
2057        $invalidClientIp = "Invalid clientip";
2058        
2059        // check error message
2060        if ($res[0] == $failureOrder || $res == $failureOrder) {
2061            $error = __("Error : 決済失敗");
2062        } else if ($res[0] == $maintenance || $res == $maintenance) {
2063            $error = __("Error : メンテナンス中");
2064        } else if ($res[0] == $connectError || $res == $connectError) {
2065            $error = __("Error : Connect Error");
2066        } else if ($res[0] == $cardNumberError || $res == $cardNumberError) {
2067            $error = __("Error : カード番号が正しくありません 半角数字で入力してください。ハイフン(-)は必要ありません。");
2068        } else if ($res[0] == $telnoError || $res == $telnoError) {
2069            $error = __("Error : 電話番号が正しくありません 半角数字で入力してください。ハイフン(-)は必要ありません。");
2070        } else if ($res[0] == $usernameError || $res == $usernameError) {
2071            $error = __("Error : クレジットカードに記載されている名前を半角英字で入力してください。");
2072        } else if ($res[0] == $invalidClientIp || $res == $invalidClientIp) {
2073            $error = __("Error : 決済失敗");
2074        } else {
2075            $error = $res;
2076        }
2077
2078        // set the flash message
2079        $this->Session->setFlash($error, array("element" => "flashfail"));
2080        
2081        // check if the referrer action exists
2082        if (is_array($referrer)) {
2083            return $this->redirect($referrer);
2084        } else {
2085            return $this->redirect(myTools::getUrl() . '/');
2086        }
2087    }
2088
2089    /**
2090     * @api {post} /payment/zeuspay/:zeus3DsecureFlg/:ordd/:money/:sendid/:email/:clientip/:sendpoint/:result/:paymentType/:formType/:payment_id/:cardnumber/:cardbrand zeuspay()
2091     * @apiName zeuspay
2092     * @apiGroup Payment
2093     * @apiDescription This endpoint is used to handle the payment process using zeuspay.
2094     * 
2095     * @apiParam {Boolean} zeus3DsecureFlg The 3D secure flag.
2096     * @apiParam {String} ordd The order id.
2097     * @apiParam {Number} money The amount of money.
2098     * @apiParam {String} sendid The user id.
2099     * @apiParam {String} email The user email.
2100     * @apiParam {String} clientip The client ip address.
2101     * @apiParam {String} sendpoint The payment hash.
2102     * @apiParam {String} result The result of the payment.
2103     * @apiParam {Number} paymentType The payment type.
2104     * @apiParam {Number} formType The form type.
2105     * @apiParam {Number} payment_id The payment id.
2106     * @apiParam {Number} cardnumber The card number.
2107     * @apiParam {String} cardbrand The card brand.
2108     * 
2109     * @apiSuccess {Database} Save Save/update the payment transaction to the database.
2110     * 
2111     * @apiError {PHP} slackZeusErrorPostMsg Sends a slack message if the source IP is not supported.
2112     * @apiError {PHP} log Logs the error if the payment hash is not set.
2113     * 
2114     * @apiSuccessExample Success Response Textbook Purchase:
2115     * Updates the textbook_sales table, inserts the payment_id
2116     * 
2117     * @apiSuccessExample Success Response Payment Receivable:
2118     * creates new payment in payment table and update/add user's settlement amount
2119     * 
2120     * @apiSuccessExample Success Response Appreciation Receivable:
2121     * creates new payment in payment table and update/add user's settlement amount
2122     * 
2123     * @apiSuccessExample Success Response Native Speaker Payment:
2124     * creates new payment in payment table and update/add user's settlement amount
2125     * 
2126     * @apiSuccessExample Success Response Callan Option Payment:
2127     * creates new payment in payment table and update/add user's settlement amount
2128     * 
2129     * @apiErrorExample Error Response Source IP not supported:
2130     * Sends a slack message if the source IP is not supported.
2131     * 
2132     * @apiErrorExample Error Response Payment Hash not set:
2133     * Logs the error if the payment hash is not set.
2134     * 
2135     * @apiSampleRequest off
2136     */
2137    public function zeuspay() {
2138
2139        $this->autoLayout = false;
2140        $this->autoRender = false;
2141
2142        App::uses('telecomcheckout','Vendor');
2143
2144        # get data
2145        $data = $this->request->query;
2146        $zeus3DSecureFlg = isset($data['zeus3DSecureFlg']) && $data['zeus3DSecureFlg'] ? true : false;
2147        
2148        // - debug
2149        if (
2150            // - if has ordd or money
2151            isset($data["ordd"]) && 
2152            isset($data["money"]) && 
2153            
2154            // - if valid ordd
2155            $data["ordd"] &&
2156            
2157            // - if valid money
2158            $data["money"] > 0
2159        ) {
2160            // - get first slack segment
2161            $slackSegments = explode("-", $data["ordd"]);
2162            
2163            // - if test card
2164            if (
2165                // - if dev, staging, local
2166                in_array(Configure::read('ENVIRONMENT'), ["DEV", "STAGING", "LOCAL"])
2167                
2168                // - not a test card
2169                && !in_array($slackSegments[0], ["TEST", "CHECK"])
2170            ) {
2171                // - send slack
2172                $mySlack = new mySlack();
2173                $mySlack->channel = myTools::checkChannel("#fdci-nativecamp", "#fdci-nativecamp");
2174                $mySlack->link_names = true;
2175                $mySlack->allow_test_channel = true;
2176                $mySlack->token = "xoxb-392902820692-6499139810404-RHHGc6Z5ZB9o2KkiGhzTTtlQ";
2177                $mySlack->text = "<!subteam^SNX2TCYAE|fdci-delivery>";
2178                $mySlack->text .= "```";
2179                $mySlack->text .= "environment: " . json_encode(Configure::read('ENVIRONMENT')) ."\n\n";
2180                $mySlack->text .= "user_id: " . ($data['sendid']) ."\n";
2181                $mySlack->text .= "email: " . ($data['email']) ."\n";
2182                $mySlack->text .= "amount: " . ($data['money']);
2183                $mySlack->text .= "```";
2184                $mySlack->postMessage();
2185            }
2186        }
2187        
2188        // check if from a valid ip address and not 3d secure callback
2189        if(
2190            !$zeus3DSecureFlg && 
2191            $_SERVER["REMOTE_ADDR"] != "210.164.6.67" && 
2192            $_SERVER["REMOTE_ADDR"] != "202.221.139.50" && 
2193            $_SERVER["REMOTE_ADDR"] != "180.232.127.154" &&
2194            $_SERVER["REMOTE_ADDR"] != "133.242.229.199"
2195        ){
2196            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, 0, 'Source IP not supported', $data);
2197            die;
2198        }
2199
2200        # load model
2201        $this->loadModel("ZPaymentSucceeded");
2202        $this->loadModel("UsersPoint");
2203        $this->loadModel("Payment");
2204        $this->loadModel("ContinuationCampaign");
2205        
2206        # set variables
2207        $telecom_zeus_convert = false;
2208        $formType = Configure::read('payment_credit_default');
2209        $card_company = Configure::read('card_company.zeus');
2210        $platform = Configure::read('platform.pclp');
2211        $receivablePayment = $liveLessonReceivable = 0;
2212        $dateNow = date("Y-m-d H:i:s");
2213        $appreciationFlg = 0;
2214        $tipAmount = null;
2215
2216        // if payment hash is not set
2217        if (!isset($data['sendpoint'])) {
2218            $this->log(__METHOD__ . ' zeus.error.no_payment_hash', 'debug');
2219            $this->_error_log_set($data);
2220            return ;
2221        }
2222
2223        // if using corporate company payment (credit card)
2224        if (strpos($data['sendid'], 'cz') !== false) {
2225            $data['usingCompanyCard'] = true;
2226            return $this->corporateZeuspay($data);
2227        }
2228
2229        // - check if paymentHash is empty
2230        if (
2231            (isset($data['result']) && strtoupper($data['result']) == "OK") &&
2232            (!$data['sendpoint'] || $data['sendpoint'] == 0) && 
2233            (isset($data['sendid']) && $data['sendid'])
2234        ) {
2235            $data['sendpoint'] = $this->memcache->get('zeus_sec_payment_hash_'.$data['sendid']);
2236        }
2237
2238        // get payment hash
2239        $paymentHash = trim($data['sendpoint']);
2240
2241        // prevent switching to replicas inside kickback
2242        $this->PaymentTransaction->setOverrideConnectFlg(true);
2243
2244        // get payment transaction
2245        $ptData = $this->PaymentTransaction->getWPPaymentTransaction($paymentHash);
2246
2247        // if pending payment transaction does not exist try to remove condition to check if has failed transation to override it
2248        if (!$ptData && strtoupper($data['result']) == 'OK') {
2249            // override the last transaction
2250            $ptData = $this->PaymentTransaction->find('first', array(
2251                'fields' => array(
2252                    'id',
2253                    'user_id',
2254                    'password',
2255                    'payment_params'
2256                ),
2257                'conditions' => array(
2258                    'payment_hash' => $paymentHash
2259                ),
2260                'recursive' => -1
2261            ));
2262
2263            if ($ptData) {
2264                $ptData = $ptData['PaymentTransaction'];
2265            }
2266        }
2267
2268        // do nothing if payment transaction (payment hash and status = 0) does not exist.
2269        if (!$ptData) {
2270            $this->log(__METHOD__ . ' Payment transaction status 0 does not exist. ' . json_encode($data), 'monthly_payment');
2271            // Send to slack only if money is greater than 0
2272            if (isset($data['money']) && $data['money'] > 0) {
2273                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, 0, 'Payment transaction status 0 does not exist', $data);
2274            }
2275            return ;
2276        }
2277
2278        // decode payment params to array
2279        $ptPaymentParams = json_decode($ptData['payment_params'], true);
2280        $familyId = isset($ptPaymentParams['familyId']) ? $ptPaymentParams['familyId'] : null;
2281        $userId = $familyId ? $familyId : $data['sendid'];
2282        $cardExpirationDate = isset($data['cardexpirationdate']) ? $data['cardexpirationdate'] : null;
2283        $logFileName = isset($ptPaymentParams['logFileName']) ? $ptPaymentParams['logFileName'] : 'monthly_payment';
2284        $basicFee = isset($ptPaymentParams['basicFee']) ? $ptPaymentParams['basicFee'] : 0;
2285        $lessonFee = isset($ptPaymentParams['lessonFee']) ? $ptPaymentParams['lessonFee'] : 0;
2286        $lessonFeeDateStarted = isset($ptPaymentParams['lessonFeeDateStarted']) ? $ptPaymentParams['lessonFeeDateStarted'] : null;
2287        $ptId = $ptData['id'];
2288        
2289        //remove from paying users memcache
2290        UserTable::removePayingUserFromMemcache($userId);
2291
2292        # check the source of the payment
2293        if (isset($ptPaymentParams['formType'])) {
2294            $formType = $ptPaymentParams['formType'];
2295        }
2296
2297        // prevent switching to replicas inside kickback
2298        $this->Payment->setOverrideConnectFlg(true);
2299        
2300        $monthlyPaymentExist = $this->Payment->find('count', array(
2301            'conditions' => array(
2302                'Payment.user_id' => $userId,
2303                'Payment.ordd' => $data['ordd'],
2304                'Payment.card_company' => Configure::read('card_company.zeus'),
2305                'Payment.form_type' => $formType
2306            )
2307        ));
2308        
2309        // NC-4036: do nothing if zeus user and monthly payment transaction (ordd) already exist.
2310        if ($monthlyPaymentExist) {
2311            $this->log(__METHOD__ . ' Payments data already exist. ' . json_encode($data), $logFileName);
2312            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Payments data already exist', $data);
2313            return ;
2314        }
2315
2316        // NC-8600: if family is withdrawn
2317        if ($formType == Configure::read('payment_credit_family_monthly_payment') && $this->memcache->get('deactivated-user-'.$userId)) {
2318            $this->log(__METHOD__ . ' User is withdrawn. ' . json_encode($data), 'monthly_payment');
2319            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'User is withdrawn', $data);
2320            return;
2321        }
2322        
2323        // save settlement history for tracking
2324        if (!SettlementHistoryTable::add(array(
2325                'userId' => $userId,
2326                'params' => json_encode($data),
2327                'createdIp' => $dateNow,
2328                'modifiedIp' => $dateNow
2329            )
2330        )) {
2331            $this->log(__METHOD__ . ' Failed to save zeuspay kickback data in settlement history. ' . json_encode($data), $logFileName);
2332            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save zeuspay kickback data in settlement history', $data);
2333            return;
2334        }
2335
2336        # append data parameters
2337        $data += array(
2338                'ip' => isset($ptPaymentParams['remoteAddress']) ? $ptPaymentParams['remoteAddress'] : null,
2339                'user_id' => $userId,
2340                'created' => $dateNow,
2341                'modified' => $dateNow,
2342        );
2343
2344        # check if user exists, and remove any bound models
2345        $userData = $this->User->find("first",array("conditions" =>array("User.id"=>$userId), "recursive" => -1));
2346        if (!$userData) {
2347            $this->log(__METHOD__ . ' User id does not exist. ' . json_encode($userId) . ' -- ' . json_encode($data), $logFileName);
2348            $data['error_code'] = Configure::read('zeus.error.no_user');
2349            $this->_error_log_set($data, $ptPaymentParams);
2350            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'User id does not exist', $data);
2351            return ;
2352        }
2353
2354        $membershipStatusIndex = UserTable::getStudentMembershipStatus($userId);
2355
2356        $paymentPlanId = isset($ptPaymentParams['paymentPlanId']) ? $ptPaymentParams['paymentPlanId'] : null;
2357
2358        if (isset($data['result']) && strtoupper($data['result']) == 'OK' && $membershipStatusIndex == 7) {
2359            $this->mySlack->channel = $this->slackChannel;
2360            $this->mySlack->username = "Zeus kickback:";
2361            $this->mySlack->text = "```";
2362            $this->mySlack->text .= date("Y/m H:i") . "\n";
2363            $this->mySlack->text .= "User : " . myTools::getUrl() . '/admin/user-manage/member/' . $userData['User']['id'] . "\n";
2364            $this->mySlack->text .= "kickback arrive on deleted user";
2365            $this->mySlack->text .= "```";
2366
2367            // send slack
2368            $this->mySlack->sendSlack();
2369        }
2370
2371        if (
2372                $paymentPlanId &&
2373                in_array(
2374                        $paymentPlanId,
2375                        array(
2376                                Configure::read('payment_plans.premium_plan'),
2377                                Configure::read('payment_plans.family_plan'),
2378                                Configure::read('payment_plans.light_plan'),
2379                                Configure::read('payment_plans.chocotto_plan')
2380                        )
2381                ) &&
2382                isset($userData['User']['corporate_id']) &&
2383                $userData['User']['corporate_id'] &&
2384                !empty($userData['User']['corporate_id']) &&
2385                in_array(
2386                        $formType,
2387                        array(
2388                                Configure::read('payment_credit_force_charge'),
2389                                Configure::read('payment_lite_credit_paid'),
2390                                Configure::read('payment_credit_chocotto_free'),
2391                                Configure::read('payment_credit_chocotto_monthly_payment'),
2392                                Configure::read('payment_credit_chocotto_retry'),
2393                                Configure::read('payment_credit_chocotto_force_charge')
2394                                )
2395                )
2396        ) {
2397            // - removed corporate id
2398            $userData['User']['corporate_id'] = null;
2399            $this->User->read(array('corporate_id'), $userId);
2400            $this->User->set(array('corporate_id' => ''));
2401            $this->User->validate = array();
2402            $this->User->save();
2403        }
2404
2405        // redirect to corporate zeuspay if corporate individual user
2406        // and form type is not equals to force charge
2407        if (
2408            isset($userData['User']['corporate_id']) &&
2409            $userData['User']['corporate_id'] &&
2410            !in_array($formType, array(Configure::read('payment_credit_force_charge'),Configure::read('payment_lite_credit_paid') , Configure::read('payment_credit_chocotto_force_charge'),Configure::read('payment_study_abroad') ) )
2411        ) {
2412            return $this->corporateZeuspay($data, true);
2413        }
2414
2415        # check if ordd is present
2416        if (isset($data['ordd']) === FALSE) {
2417            $data['ordd'] = NULL;
2418        }
2419
2420        # check clientip if url is from zeus
2421        if ($data['clientip'] == Configure::read('ZEUS_clientip')) {
2422            $card_company = Configure::read('card_company.zeus');
2423        }
2424
2425        # check if payment transaction password exist
2426        $ptPassword = "";
2427        if (isset($ptData['password'])) {
2428            $ptPassword = $ptData['password'];
2429        }
2430
2431        # check if payment type is from payment plan or coin purchase or textbook purchase
2432        if (isset($ptPaymentParams['paymentType'])) {
2433            $paymentType = $ptPaymentParams['paymentType'];
2434        }
2435
2436        # check platform
2437        if (isset($ptPaymentParams['platform'])) {
2438            $platform = $ptPaymentParams['platform'];
2439        }
2440
2441        $priceId = isset($ptPaymentParams['priceId']) ? $ptPaymentParams['priceId'] : null;
2442        $currencyCode = isset($ptPaymentParams['currencyCode']) ? $ptPaymentParams['currencyCode'] : Configure::read('currency_jpy');
2443        $discounted_amount = isset($ptPaymentParams['discounted_amount']) ? $ptPaymentParams['discounted_amount'] : 0;
2444
2445        // if using coupon during force settlement
2446        if (!empty($ptPaymentParams['couponUseSettlement']) && !empty($ptPaymentParams['couponUseSettlement']['useCouponAmount']) && in_array($formType, Configure::read('allow_coupon.settlement_form_type'))) {
2447            $discounted_amount += $ptPaymentParams['couponUseSettlement']['useCouponAmount'];
2448        }
2449
2450        # NC-8194: check null payment_plan_id and price_id
2451        if (!$paymentPlanId || !$priceId) {
2452            if ( $userData['User']['payment_plan_id'] && $userData['User']['price_id']) {
2453                $paymentPlanId = $userData['User']['payment_plan_id'];
2454                $priceId = $userData['User']['price_id'];
2455            } else {
2456                $defPlan = $this->PaymentPlanPrice->getDefaultPlan($userData['User']);
2457                $paymentPlanId = $defPlan['paymentPlanId'];
2458                $priceId = $defPlan['priceId'];
2459            }
2460        }
2461
2462        # set data variables
2463        $data['paymentType'] = $paymentType;
2464        $data['formType'] = $formType;
2465
2466        // - NJ-18780 : check if lite plan user 
2467        $isLitePlanUser = in_array($paymentPlanId, Configure::read('lite_payment_plans')) ? true : false;
2468
2469        $cronDateRun = $dateNow;
2470        // hotfix_NC-3152: add cronDateRun
2471        if (isset($ptPaymentParams['cronDateRun'])) {
2472            $cronDateRun = date('Y-m-d 00:20:00');
2473        }
2474
2475        $monthlyPayment = isset($data["money"]) ? $data["money"] : 0;
2476        $nativeOptionPayment = 0;
2477        $callanOptionPayment = 0;
2478
2479        
2480        // if monthly payment, retry or force charge
2481        // check if user has receivable payment
2482        if (in_array($formType, array(
2483            Configure::read('payment_credit_monthly_payment'),
2484            Configure::read('payment_credit_family_monthly_payment'),
2485            Configure::read('payment_credit_force_charge'),
2486            Configure::read('payment_credit_retry'),
2487            Configure::read('payment_lite_credit_monthly_payment'),
2488            Configure::read('payment_lite_credit_paid'),
2489            Configure::read('payment_lite_plan_downgrade'),
2490            Configure::read('payment_lite_plan_upgrade'),
2491            Configure::read('payment_credit_change'),
2492            Configure::read('payment_credit_chocotto_monthly_payment'),
2493            Configure::read('payment_credit_chocotto_retry'),
2494            Configure::read('payment_credit_chocotto_force_charge')
2495        ))) {
2496
2497            $_allowChangePlan = true;
2498
2499            if (
2500                $formType == Configure::read('payment_lite_plan_downgrade') || 
2501                $formType == Configure::read('payment_lite_plan_upgrade')
2502            ) {
2503                $_allowChangePlan = false;// default 
2504
2505                if (isset($ptPaymentParams['changePlanChargeFlg']) && $ptPaymentParams['changePlanChargeFlg']) {
2506                    $_allowChangePlan = true;
2507                }
2508            }
2509
2510            // compute receivable payments
2511            $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userData['User']['id'], $cronDateRun);
2512
2513            // if has receivable payment
2514            // deduct said monthly settlement from the money sent to zeus
2515            if ($receivablePayment && $receivablePayment <= $data["money"] && $_allowChangePlan) {
2516                // deduct from monthly payment
2517                $monthlyPayment -= $receivablePayment;
2518            }
2519
2520            // if has native speaker payments
2521            // deduct
2522            if (isset($ptPaymentParams['nativeOptionPayment']) && $ptPaymentParams['nativeOptionPayment'] > 0 && $_allowChangePlan) {
2523                $nativeOptionPayment = $ptPaymentParams['nativeOptionPayment'];
2524                $monthlyPayment -= $nativeOptionPayment;
2525            }
2526
2527            // if has callan option payments
2528            // deduct
2529            if (isset($ptPaymentParams['callanOptionPayment']) && $ptPaymentParams['callanOptionPayment'] > 0 && $_allowChangePlan) {
2530                $callanOptionPayment = $ptPaymentParams['callanOptionPayment'];
2531                $monthlyPayment -= $callanOptionPayment;
2532            }
2533
2534            // compute appreciation receivable payments
2535            $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.appreciation'));
2536
2537            if ($appreciationReceivable && $appreciationReceivable <= $monthlyPayment) {
2538                $monthlyPayment -= $appreciationReceivable;
2539            }
2540
2541            // compute live lesson receivable payments
2542            $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userData['User']['id'], $cronDateRun, Configure::read('payment_element_type.live'));
2543
2544            if ($liveLessonReceivable && $liveLessonReceivable <= $monthlyPayment && $_allowChangePlan) {
2545                $monthlyPayment -= $liveLessonReceivable;
2546            }            
2547
2548            $ptPaymentParams['paymentAmount'] = $monthlyPayment;
2549        }
2550
2551        // Check receivables combine on `payment_credit_receivable` form type
2552        if( $formType == Configure::read('payment_credit_receivable') ) {
2553
2554            // compute appreciation receivable payments
2555            $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.appreciation'));
2556
2557            // deduct said receivable settlement from the money sent to zeus
2558            if ($appreciationReceivable && $appreciationReceivable <= $data["money"]) {
2559                // deduct from receivable payment
2560                $monthlyPayment -= $appreciationReceivable;
2561            }
2562
2563            // compute live receivable payments
2564            $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.live'));
2565
2566            // deduct said receivable settlement from the money sent to zeus
2567            if ($liveLessonReceivable && $liveLessonReceivable <= $data["money"]) {
2568                // deduct from receivable payment
2569                $monthlyPayment -= $liveLessonReceivable;
2570            }            
2571
2572            $ptPaymentParams['paymentAmount'] = $monthlyPayment;
2573        }
2574
2575        $kbResult = false;
2576        # check if the result is ok
2577        if ( strtoupper($data['result']) == 'OK' ) {
2578            $kbResult = true;
2579            $this->log(__METHOD__ . 'result is ok', $logFileName);
2580
2581            # get current card company
2582            $currentCardCompany = is_null($userData['User']['card_company']) ? FALSE : intVal($userData['User']['card_company']);
2583
2584            # if user is with telecom, withdraw
2585            if (
2586                (
2587                    $formType != Configure::read('payment_credit_coin_purchase') && 
2588                    $formType != Configure::read('payment_credit_textbook_purchase') && 
2589                    $formType != Configure::read('payment_credit_receivable') &&
2590                    $formType != Configure::read('payment_credit_appreciation_receivable') &&
2591                    $formType != Configure::read('payment_native_option_join') &&
2592                    $formType != Configure::read('payment_native_option_monthly_payment') &&
2593                    $formType != Configure::read('payment_callan_option_join') &&
2594                    $formType != Configure::read('payment_callan_option_monthly_payment') &&
2595                    $formType != Configure::read('payment_study_abroad')
2596                ) &&
2597                $currentCardCompany !== FALSE &&
2598                $currentCardCompany == Configure::read('card_company.telecom')
2599            ) {
2600                # perform withdrawal
2601                $telecom = new telecomcheckout();
2602
2603                # get past payment transactions
2604                $paymentTransaction = $this->PaymentTransaction->find("all",
2605                    array(
2606                        "conditions" => array (
2607                            "user_id" => $userData['User']["id"]
2608                        ),
2609                        "order" => "id ASC"
2610                    )
2611                );
2612
2613                # check if payment transactions exists
2614                if ($paymentTransaction) {
2615                    # loop through each payment transactions
2616                    foreach ( $paymentTransaction as $sendpass) {
2617                        # set telecom params
2618                        $telecom->setParams(array(
2619                                'sendid'   => $userData['User']['hash16'],
2620                                'sendpass' => $sendpass["PaymentTransaction"]["password"],
2621                        ));
2622
2623                        # get result
2624                        $res = $telecom->setDeactivation();
2625
2626                        # check if withdrawal from telecom was ok
2627                        if (strtoupper($res) === 'OK') {
2628                            $this->User->set('id', $userData['User']['id']);
2629                            $this->User->set('charge_flg', 0);
2630                            $this->User->set('card_company', $card_company);
2631                            $this->User->set('modified', date('YmdHis'));
2632                            $this->User->save();
2633                            $telecom_zeus_convert = true;
2634                            break;
2635                        }
2636                    }
2637                }
2638
2639                # check if the conversion worked
2640                if($telecom_zeus_convert == false){
2641                    $this->mySlack->channel = $this->slackChannel;
2642                    $this->mySlack->username = "Payment Withdrawal :";
2643                    $this->mySlack->text = "```";
2644                    $this->mySlack->text .= date("Y/m H:i") . "\n";
2645                    $this->mySlack->text .= "User : " . $userData['User']['id'] . "\n";
2646                    $this->mySlack->text .= "Withdrawal failed. Please withdraw manually.";
2647                    $this->mySlack->text .= "```";
2648
2649                    // send slack
2650                    $this->mySlack->sendSlack();
2651
2652                    # save error to database
2653                    /*$data['error_code'] = Configure::read('zeus.error.telecom_fail_withdrawal');
2654                    $this->_error_log_set($data);
2655                    echo "TelecomFailureWithdrawal";*/
2656
2657                } else {
2658                    $this->mySlack->channel = $this->slackChannel;
2659                    $this->mySlack->username = "Payment Withdrawal :";
2660                    $this->mySlack->text = "```";
2661                    $this->mySlack->text .= date("Y/m H:i") . "\n";
2662                    $this->mySlack->text .= "User " . $userData['User']['id'] . " succesfully withdrew from telecom!\n";
2663                    $this->mySlack->text .= "```";
2664
2665                    // send slack
2666                    $this->mySlack->sendSlack();
2667                }
2668            }
2669
2670            # check if formType = 5
2671            if ($formType == Configure::read('payment_credit_coin_purchase') && isset($ptPaymentParams['coinPurchasePoints'])) {
2672                
2673                $coinPurchasePoints = intVal($ptPaymentParams['coinPurchasePoints']);
2674                $coinData = $this->UsersPoint->SET_charge_overseas_menue($coinPurchasePoints, $currencyCode);
2675
2676                // NC-5007 add to the user's existing coin
2677                $pcZeusPay = array(
2678                    'userId' => $userData['User']['id'],
2679                    'point' => $coinData['num_of_coin'] - $coinData['bonus_coin'],
2680                    'kbn' => 7,
2681                    'kbnType' => 1, // add coin
2682                    'coinType' => 1, // purchase coin
2683                    'coinFailMessage' => Configure::read('coin.failed.buy_coin'),
2684                    'device' => isset($ptPaymentParams['device']) ? $ptPaymentParams['device'] : null
2685                );
2686
2687                $scZeusPay = array(
2688                    'userId' => $userData['User']['id'],
2689                    'point' => $coinData['bonus_coin'],
2690                    'kbn' => 7,
2691                    'kbnType' => 1, // add coin
2692                    'coinType' => 2, // service coin
2693                    'coinFailMessage' => Configure::read('coin.failed.buy_coin'),
2694                    'device' => isset($ptPaymentParams['device']) ? $ptPaymentParams['device'] : null
2695                );
2696
2697                $pointParams = [$pcZeusPay, $scZeusPay];
2698
2699                if ( $pointParams ) {
2700                    foreach($pointParams as $key => $val) {
2701                        if (!$this->UsersPoint->performPointTransaction($val)) {
2702                            $this->log(__METHOD__ . ' Failed to add user point. ' . json_encode($val) . ' -- ' . json_encode($data), $logFileName);
2703                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to add user point', $data, $val);
2704                            return ;
2705                        }
2706                    }
2707                }
2708            }
2709
2710            // check if family plan and a coin purchase form type 
2711            if (
2712                $familyId 
2713                && in_array($formType, array(
2714                        Configure::read('payment_credit_coin_purchase'), 
2715                        Configure::read('payment_credit_textbook_purchase')
2716                    )
2717                )
2718            ) {
2719                // change reference id to parent id
2720                $referenceId = isset($data['sendid']) ? $data['sendid'] : 0;
2721            
2722            //IF Native option or callan option join payment and family
2723            } elseif(
2724                (
2725                    isset($ptPaymentParams['nativeOptionJoin']) 
2726                    && $ptPaymentParams['nativeOptionJoin'] 
2727                    && $familyId
2728                    && $ptPaymentParams['formType'] == Configure::read('payment_native_option_join')
2729                ) 
2730                ||
2731                (
2732                    isset($ptPaymentParams['callanOptionJoin']) 
2733                    && $ptPaymentParams['callanOptionJoin'] 
2734                    && $familyId
2735                    && $ptPaymentParams['formType'] == Configure::read('payment_callan_option_join')
2736                )
2737            ) {
2738                // change reference id to parent id
2739                $referenceId = isset($data['sendid']) ? $data['sendid'] : 0;
2740            } else {
2741                $referenceId = $userId;
2742            }
2743            
2744            $paymentData = array(
2745                'user_id' => $userId,
2746                'amount' => $monthlyPayment,
2747                'status' => 1,
2748                'reference_id' => $referenceId,
2749                'payment_transaction_password' => $ptPassword,
2750                'card_company' => $card_company,
2751                'param1' => json_encode($data),
2752                'form_type' => $formType,
2753                'ordd' => $data["ordd"],
2754                'transaction_code' => $paymentHash,
2755                'currency_id' => Configure::read('default.settlement_currency_id'), // set currency id to jpy
2756                'currency_code' => $currencyCode,
2757                'payment_id' => $paymentPlanId,
2758                'price_id' => $priceId,
2759                'payment_type' => $paymentType
2760            );
2761            
2762            $discountOption = isset($ptPaymentParams['discountOption']) ? $ptPaymentParams['discountOption'] : [];
2763            
2764            if (!empty($discountOption)) {
2765                $paymentData['discount_option_price_id'] = $discountOption['discount_option_price_id'];
2766            }
2767            
2768            // NJ-47740
2769            $discountType = 'monthly';
2770            if ($formType == Configure::read('payment_native_option_join')) {
2771                $discountType = 'native';
2772            } else if ($formType == Configure::read('payment_callan_option_join')) {
2773                $discountType = 'callan';
2774            } else if ($formType == Configure::read('payment_credit_coin_purchase')) {
2775                $discountType = 'coin';
2776            }
2777            
2778            $getCouponDiscounDetail = PaymentTable::getCouponDiscountRequestDetail($ptPaymentParams, $discountType);
2779            $paymentData['discounted_amount'] = !empty($getCouponDiscounDetail['discounted_amount']) ? $getCouponDiscounDetail['discounted_amount'] : 0;
2780            $paymentData['coupon_request_id'] = !empty($getCouponDiscounDetail['coupon_request_id']) ? $getCouponDiscounDetail['coupon_request_id'] : null;
2781            
2782            $forceSettlementWithCoupon  = false;
2783            // if using coupon during force settlement
2784            if (
2785                !empty($ptPaymentParams['couponUseSettlement']) && 
2786                !empty($ptPaymentParams['couponUseSettlement']['useCouponAmount']) && 
2787                in_array($formType, Configure::read('allow_coupon.settlement_form_type'))
2788            ) {
2789                // apply coupon use discount
2790                $couponData = $ptPaymentParams['couponUseSettlement'];
2791                $couponData['nextChargeDate'] = date('Y-m-d');
2792                $couponData['request_result'] = true;
2793
2794                $result_coupon_use = $this->UsersCouponV1->performCouponUse($couponData);
2795                $result_coupon_use = !empty($result_coupon_use) ? json_decode($result_coupon_use,true) : array();
2796                
2797                if (empty($result_coupon_use)) {
2798                    $this->log(__METHOD__ . ' Failed to used coupons.' . json_encode($couponData), $logFileName);
2799                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to used coupons.', $couponData, array_merge($_POST, $_SERVER));
2800                    return false;
2801                }
2802                
2803                $paymentData['discounted_amount'] = $ptPaymentParams['couponUseSettlement']['useCouponAmount'];
2804                $paymentData['coupon_request_id'] = isset($result_coupon_use['cgrp_id']) ? $result_coupon_use['cgrp_id'] : null;
2805                
2806                $forceSettlementWithCoupon = true;
2807            }
2808            // NJ-47740 - end
2809            
2810            // NC-10009 95% OFF new year campaign
2811            // During NC-10009 campaign 
2812            // Temporary -> Premiuim Plan Paid
2813            // Create two payment data for card authentication and for premium plan paid payment
2814            $newYear95percentOffCampaign = false;
2815            if (
2816                (isset($ptPaymentParams['campaign95percentOff']) && $ptPaymentParams['campaign95percentOff'])
2817                && (isset($ptPaymentParams['userRegister']) && $ptPaymentParams['userRegister'])
2818            ) 
2819            {
2820                $newYear95percentOffCampaign = true;
2821                $paymentDataForCardAuthentication = $paymentData;
2822                $paymentDataForCardAuthentication['amount'] = 0;
2823                $paymentDataForCardAuthentication['form_type'] = Configure::read('payment_credit_authentication');
2824                $paymentDataForCardAuthentication['payment_id'] = Configure::read('payment_plans.free_trial');
2825                $paymentDataForCardAuthentication['price_id'] = 1;
2826                // create new for card authentication payment
2827                $this->Payment->clear();
2828                $this->Payment->create();
2829                $this->Payment->set($paymentDataForCardAuthentication);
2830                $this->Payment->save();
2831            }
2832
2833            //- check payment receivable with zero amount
2834            if (
2835                $formType == Configure::read('payment_credit_receivable') &&
2836                $monthlyPayment <= 0
2837            ) {
2838                //- skip saving
2839            } else {
2840                // create new payment
2841                $this->Payment->clear();
2842                $this->Payment->create();
2843                $this->Payment->set($paymentData);
2844                $savePaymentData = $this->Payment->save();
2845
2846                //update/add user`s settlement amount
2847                $this->User->updateUserPayments($paymentData);
2848                // check if payment was not saved
2849                if (!$this->Payment->save()) {
2850                    $this->log(__METHOD__ . ' Failed to save payment data. ' . json_encode($paymentData) . ' -- ' . json_encode($data), $logFileName);
2851                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data', $data, $paymentData);
2852                    
2853                    // if payment failed and has coupon grp id and its direct payment -> unconfirm coupon
2854                    if (
2855                        isset($paymentData['coupon_request_id']) && $paymentData['coupon_request_id'] &&
2856                        (
2857                            // the native or callan purchase with coupon use already has checker while processing the payment
2858                            // to ensure that payment errors are caught, place it here as well to make sure that the coupon is unconfirmed in case the page is refreshed while processing
2859                            in_array(
2860                                $formType, array(
2861                                    Configure::read('payment_native_option_join'),
2862                                    Configure::read('payment_callan_option_join'),
2863                                    Configure::read('payment_credit_coin_purchase')
2864                                )
2865                            ) ||
2866                            // force settlement with coupon
2867                            $forceSettlementWithCoupon
2868                        )
2869                    ) {
2870                        $couponKbn = Configure::read('coupon_kbn.coin_purchase'); // default
2871                        if ($formType == Configure::read('payment_native_option_join')) {
2872                            $couponKbn = Configure::read('coupon_kbn.native_option');
2873                        } else if ($formType == Configure::read('payment_callan_option_join')) {
2874                            $couponKbn = Configure::read('coupon_kbn.callan_option');
2875                        } else if ($forceSettlementWithCoupon) {
2876                            $couponKbn = Configure::read('coupon_kbn.monthly_settlement');
2877                        }
2878                        
2879                        $res_unconfirm = $this->UsersCouponV1->performCouponUnconfirm(array(
2880                            'grpId' => $paymentData['coupon_request_id'],
2881                            'userId' => $userId,
2882                            'kbn' => $couponKbn
2883                        ));
2884
2885                        if (empty($res_unconfirm)) {
2886                            $this->log(__METHOD__ . ' failed to perform coupon unconfirm.', $logFileName);
2887                        }
2888                    }
2889                    return ;
2890                }
2891                
2892                // update payment details
2893                $updatePaymentDetailParams = array(
2894                    'currencyCode' => $paymentData['currency_code'],
2895                    'formType' => $paymentData['form_type'],
2896                    'paymentType' => $paymentData['payment_type'],
2897                    'amount' => $paymentData['amount'],
2898                    'discounted_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0,
2899                    'familyId' => $familyId,
2900                    'cronDateRun' => $cronDateRun,
2901                    'priceId' => $paymentData['price_id'],
2902                    'paymentPlanId' => $paymentData['payment_id'],
2903                    'user_id' => $paymentData['user_id'],
2904                    'coupon_use_request_id' => isset($paymentData['coupon_request_id']) ? $paymentData['coupon_request_id'] : null,
2905                    'coupon_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0
2906                );
2907                
2908                if (!empty($discountOption)) {
2909                    $updatePaymentDetailParams['discount_option_price_id'] = $discountOption['discount_option_price_id'];
2910                    $updatePaymentDetailParams['discount_option_amount'] = $discountOption['amount'];
2911                }
2912                $updatePaymentDetail = array(
2913                    'id' => $ptId,
2914                    'fields' => array(
2915                        'payment_details' => $updatePaymentDetailParams
2916                    )
2917                );
2918
2919                if (!$this->PaymentTransaction->updateWPPaymentTransaction($updatePaymentDetail)) {
2920                    $this->log(__METHOD__ . ' Failed to update payment details. ' . json_encode($updatePaymentDetail), $logFileName);
2921                }
2922
2923                // set payment_id
2924                $paymentSaveID = $this->Payment->id;
2925                
2926                // NJ-47740
2927                if (!empty($paymentData['coupon_request_id']) && $paymentData['discounted_amount'] > 0) {
2928                    // confirm coupon use request for discount
2929                    $requestCouponConfirmData = array(
2930                        'grpId' => $paymentData['coupon_request_id'],
2931                        'paymentId' => $paymentSaveID
2932                    );
2933                    $result_confirm = $this->UsersCouponV1->performCouponConfirm($requestCouponConfirmData);
2934                    
2935                    if (!$result_confirm) {
2936                        $this->log(__METHOD__ . ' Failed to confirm coupon use request. ' . json_encode($requestCouponConfirmData) . ' -- ' . json_encode($data), $logFileName);
2937                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to confirm coupon use request', $data, $requestCouponConfirmData);
2938                        return ;
2939                    }
2940                }
2941                // NJ-47740 end
2942                
2943                // NJ-35237
2944                if (!empty($ptPaymentParams['rewardedPoints'])) {
2945                    $rewaredPointParams['ContinuationRewardPoint'] = $ptPaymentParams['rewardedPoints'];
2946                    // save reward point
2947                    if (!$this->ContinuationRewardPoint->saveRewardPoint($rewaredPointParams)) {
2948                        $this->log(__METHOD__ . ' Failed to save reward point. --> ' . json_encode($rewaredPointParams), $this->logFileName);
2949                    }
2950                }
2951                // NJ-35237 end
2952            }
2953
2954            if (
2955                $formType != Configure::read('payment_credit_textbook_purchase') &&
2956                $formType != Configure::read('payment_credit_receivable') &&
2957                $formType != Configure::read('payment_credit_appreciation_receivable') &&
2958                $formType != Configure::read('payment_credit_coin_purchase') &&
2959                $formType != Configure::read('payment_native_option_join') &&
2960                $formType != Configure::read('payment_native_option_monthly_payment') &&
2961                $formType != Configure::read('payment_callan_option_join') &&
2962                $formType != Configure::read('payment_callan_option_monthly_payment') &&
2963                $formType != Configure::read('payment_halfway_termination_of_annual_discount_option') &&
2964                $formType != Configure::read('payment_study_abroad')
2965            ) {
2966
2967                # user array to be saved
2968                $saveUserArr = array(
2969                    'User' => array(
2970                        'status' => 1,
2971                        'modified' => date('YmdHis'),
2972                        'fail_flg' => 0,
2973                        'charge_flg' => 1,
2974                        'counseling_attended_flg' => 0,
2975                        'card_company' => $card_company,
2976                        'hash16' => $userData['User']['id'],
2977                        'last_charge_date' => date('YmdHis'),
2978                        'card_number' => $data['cardnumber'], // NC-3914
2979                        'card_brand' => $data['cardbrand'], // NC-3914
2980                        'payment_plan_id' => $paymentPlanId,
2981                        'price_id' => $priceId,
2982                        'corporate_id' => null,
2983                        'corporate_type' => null,
2984                        'paypal_billing_agreement_id' => null,
2985                        'paypal_payer_id' => null,
2986                        'is_new_premium_flg' => 0,
2987                        'double_check_flg' => 1
2988                    )
2989                );
2990
2991                // if not empty card expiration date
2992                if (isset($ptPaymentParams['cardExpirationDate'])) {
2993                    $saveUserArr['User']['card_expiration_date'] = $ptPaymentParams['cardExpirationDate'];
2994                }
2995
2996                // set child card expiration date same as parent
2997                if (isset($ptPaymentParams['family_data']['applyPlan']['card_expiration_date'])) {
2998                    $saveUserArr['User']['card_expiration_date'] = $ptPaymentParams['family_data']['applyPlan']['card_expiration_date'];
2999                }
3000
3001                // ----
3002                # check payment if credit authentication
3003                if (
3004                    in_array(
3005                        $formType, 
3006                        [
3007                            Configure::read('payment_lite_credit_free'),
3008                            Configure::read('payment_credit_authentication'),
3009                            Configure::read('payment_credit_family_free'),
3010                            Configure::read('payment_credit_chocotto_free')
3011                        ]
3012                    )
3013                ) {
3014                    $saveUserArr['User']['first_charge_date'] = date('Y-m-d H:i:s');
3015                    $saveUserArr['User']['platform'] = $platform;
3016                // if complimentary plan unsubscribe and resubscribe
3017                } elseif (isset($ptPaymentParams['updateFirstChargeDate']) || $newYear95percentOffCampaign) {
3018                    $saveUserArr['User']['first_charge_date'] = date('Y-m-d H:i:s');
3019                }
3020
3021                // if bonus coin flg is set
3022                if (isset($ptPaymentParams['bonusCoinFlg'])) {
3023                    $saveUserArr['User']['bonus_coin_flg'] = $ptPaymentParams['bonusCoinFlg'];
3024                }
3025                //NJ-7874 if appreciation flag and amount is set
3026                if (isset($ptPaymentParams['family_data']['applyPlan']['tip_max_amount']) && $ptPaymentParams['family_data']['applyPlan']['tip_max_amount']) {
3027                    $tipAmount = $ptPaymentParams['family_data']['applyPlan']['tip_max_amount'];
3028                }
3029
3030                if (isset($ptPaymentParams['family_data']['applyPlan']['allow_appreciation_flg']) && $ptPaymentParams['family_data']['applyPlan']['allow_appreciation_flg'] && $tipAmount) {
3031                    $appreciationFlg = 1;
3032                }
3033                
3034                # check if subscription payment
3035                if (
3036                    $formType == Configure::read('payment_credit_force_charge') ||
3037                    $formType == Configure::read('payment_credit_retry') ||
3038                    $formType == Configure::read('payment_credit_monthly_payment') ||
3039                    $formType == Configure::read('payment_credit_family_monthly_payment') ||
3040                    $formType == Configure::read('payment_credit_family_free') || 
3041                    $formType == Configure::read('payment_lite_credit_monthly_payment') || 
3042                    $formType == Configure::read('payment_lite_credit_paid') ||
3043                    $formType == Configure::read('payment_credit_chocotto_monthly_payment') ||
3044                    $formType == Configure::read('payment_credit_chocotto_retry') ||
3045                    $formType == Configure::read('payment_credit_chocotto_force_charge')
3046                ) {
3047                    # get and set next charge date
3048                    $nextChargeDate = $this->User->getNextChargeDate();
3049                    $saveUserArr['User']['next_charge_date'] = $nextChargeDate;
3050                    $saveUserArr['User']['double_check_flg'] = 1;
3051                    $saveUserArr['User']['expired_card_flg'] = 0; // NC-3902
3052
3053                    // NJ-1562 - appreciation on
3054                    if( $paymentPlanId && in_array( $paymentPlanId, Configure::read('appreciation.payment_plan_id') ) ) {
3055                        //$saveUserArr['User']['allow_appreciation_flg'] = 1; // on
3056                        if (in_array($paymentPlanId,Configure::read('appreciation.can_coin_purchase_check')) ) {
3057                            //set the appreciation flg to be set
3058                            $saveUserArr['User']['allow_appreciation_flg'] = $appreciationFlg;
3059                            $saveUserArr['User']['show_appreciation_flg'] = $appreciationFlg;
3060                            $saveUserArr['User']['tip_max_amount'] = $tipAmount;
3061                        }else{
3062                            $saveUserArr['User']['allow_appreciation_flg'] = 1; // on
3063
3064                            if (
3065                                $formType == Configure::read('payment_credit_force_charge') || 
3066                                $formType == Configure::read('payment_credit_retry') || 
3067                                $formType == Configure::read('payment_lite_credit_paid')
3068                            ) {
3069                                $showAppreciationFlg = 0;//set  the default show appreciation flg
3070
3071                                //NJ-7548 : check user birthday and age ; $userData['User']['birthday']
3072                                $userAge = UserTable::getStudentAge($userData['User']['birthday']);
3073                                $userAge = $userAge ? (int) $userAge : null;
3074
3075                                //change the show appreciation flg if no birthday set or 18 and above
3076                                if (!$userAge || $userAge >= 18) {
3077                                    $showAppreciationFlg = 1;
3078                                }
3079
3080                                $saveUserArr['User']['show_appreciation_flg'] = $showAppreciationFlg; // on
3081                            }
3082                        }
3083                    }
3084                    
3085                    if ($formType == Configure::read('payment_credit_family_free')) {
3086                        $nextChargeDate = $this->User->getFirstNextChargeDate();
3087                        $saveUserArr['User']['next_charge_date'] = $nextChargeDate;
3088                    }
3089
3090                    # give points to user join the campaign who retry payment
3091                    if ($formType == Configure::read('payment_credit_retry') && !$isLitePlanUser) {
3092                        $this->ContinuationCampaign->givePointsRetrySuccess(array(
3093                            'user_ids' => array($userData['User']['id'])
3094                        ));
3095                    }
3096
3097                    # give points if user join campaign and success payment
3098                    if ($formType == Configure::read('payment_credit_monthly_payment')) {
3099                        $this->ContinuationCampaign->givePoints(array(
3100                            'user_id' => $userData['User']['id']
3101                        )); 
3102                    }
3103
3104                    # give coins if temporary/new user is changed/added to family plan
3105                    if ($formType == Configure::read('payment_credit_family_free') && $userData['User']['status'] == 0) {
3106                        // NJ-4746: defult bonus point
3107                        $defaultBC = ClassRegistry::init("DefaultCoinRegistration")->defaultCoins();
3108                        $bonusPoints = (($defaultBC > 0) ? $defaultBC : Configure::read("credit.bonus_coin_authentication"));
3109
3110                        // camapaign master triiger 1
3111                        $campaignMaster = ClassRegistry::init('CampaignMaster')->bonusTrigger(['userId' => $userData['User']['id'], 'triggerNo' => 1]);
3112                        if (!$campaignMaster['bonusCoins'] && !$campaignMaster['bonusCoupons']) {
3113                            # add to the user's existing coin
3114                            $pointParams = array(
3115                                'userId' => $userData['User']['id'],
3116                                'point' => $bonusPoints,
3117                                'kbn' => Configure::read("point_history.bonus"),
3118                                'kbnType' => 1, // add coin
3119                                'coinType' => 2, // service coin
3120                                'coinFailMessage' => Configure::read('coin.failed.campaign')
3121                            );
3122                            if (!$this->UsersPoint->performPointTransaction($pointParams)) {
3123                                $this->log(__METHOD__ . ' Failed add point to user. ' . json_encode($pointParams) . ' -- ' . json_encode($data), $logFileName);
3124                                $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed add point to user', $data, $pointParams);
3125                                return ;
3126                            }
3127                        }
3128                    }
3129
3130                    # give points if user join retry payment lite 
3131                    if ($formType == Configure::read('payment_credit_retry') && $isLitePlanUser) {
3132                        $this->liteUserAddCoinRewardForReenroll(array('id' => $userData['User']['id']));
3133                    }
3134
3135                } elseif (
3136                    $formType ==  Configure::read('payment_credit_authentication') || 
3137                    $formType == Configure::read('payment_lite_credit_free') ||
3138                    $formType == Configure::read('payment_credit_chocotto_free')
3139                ) {
3140                    // Normal user
3141                    $nextChargeDate = $this->User->getFirstNextChargeDate();
3142                    $saveUserArr['User']['next_charge_date'] = $nextChargeDate;
3143
3144                    // NJ-1562 - appreciation on
3145                    if( $paymentPlanId && in_array( $paymentPlanId, Configure::read('appreciation.payment_plan_id') ) ) {
3146                        //$saveUserArr['User']['allow_appreciation_flg'] = 1; // on
3147                        if (in_array($paymentPlanId,Configure::read('appreciation.can_coin_purchase_check')) ) {
3148                            //set the appreciation flg to be set
3149                            $saveUserArr['User']['allow_appreciation_flg'] = $appreciationFlg;
3150                            $saveUserArr['User']['show_appreciation_flg'] = $appreciationFlg;
3151                            $saveUserArr['User']['tip_max_amount'] = $tipAmount;
3152                        }else{
3153                            $saveUserArr['User']['allow_appreciation_flg'] = 1; // on
3154
3155                            $showAppreciationFlg = 0;
3156
3157                            //NJ:7548: fetch the age of the user
3158                            $uAge = UserTable::getStudentAge($userData['User']['birthday']);
3159                            $uAge = $uAge ? (int) $uAge : null;
3160
3161                            //change the show appreciation flg if no birthday set or 18 and above
3162                            if (!$uAge || $uAge >= 18) {
3163                                $showAppreciationFlg = 1;
3164                            }
3165
3166                            //set the save user array 
3167                            $saveUserArr['User']['show_appreciation_flg'] = $showAppreciationFlg; // set
3168                        }
3169                    }
3170                }
3171
3172                #NJ-7548 : if credit card changed to zeus 
3173                if (
3174                    $formType == Configure::read('payment_credit_change') && 
3175                    $paymentPlanId && in_array( $paymentPlanId, Configure::read('appreciation.payment_plan_id') )
3176                ) {
3177                    
3178                    if (in_array($paymentPlanId,Configure::read('appreciation.can_coin_purchase_check')) ) {
3179                        //set the appreciation flg to be set
3180                        $saveUserArr['User']['allow_appreciation_flg'] = $appreciationFlg;
3181                        $saveUserArr['User']['show_appreciation_flg'] = $appreciationFlg;
3182                        $saveUserArr['User']['tip_max_amount'] = $tipAmount;
3183                    }else{
3184                        $saveUserArr['User']['allow_appreciation_flg'] = 1; // on
3185
3186                        $showAppreciationFlg = 0;//set  the default show appreciation flg
3187
3188                        //NJ-7548 : check user birthday and age ; $userData['User']['birthday']
3189                        $userAge = UserTable::getStudentAge($userData['User']['birthday']);
3190                        $userAge = $userAge ? (int) $userAge : null;
3191
3192                        //change the show appreciation flg if no birthday set or 18 and above
3193                        if (!$userAge || $userAge >= 18) {
3194                            $showAppreciationFlg = 1;
3195                        }
3196
3197                        $saveUserArr['User']['show_appreciation_flg'] = $showAppreciationFlg; // on
3198                    }
3199                }
3200
3201
3202                // if credit card change from android or apple
3203                if (
3204                    in_array($formType, array(Configure::read('payment_credit_change'), Configure::read('payment_credit_authentication'))) &&
3205                    in_array($userData['User']['card_company'], array(Configure::read('card_company.apple'), Configure::read('card_company.google')))
3206                ) {
3207                    // NC-5007 add to user's existing number of coins
3208                    $pointParams = array(
3209                        'userId' => $userData['User']['id'],
3210                        'point' => 500,
3211                        'kbn' => 6,
3212                        'kbnType' => 1, // add coin
3213                        'coinType' => 2, // service coin
3214                        'coinFailMessage' => Configure::read('coin.failed.campaign')
3215                    );
3216                    if (!$this->UsersPoint->performPointTransaction($pointParams)) {
3217                        $this->log(__METHOD__ . ' Failed add point to user. ' . json_encode($pointParams) . ' -- ' . json_encode($data), $logFileName);
3218                        $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed add point to user', $data, $pointParams);
3219                        return ;
3220                    }
3221
3222                    // log for debugging
3223                    $this->log("[ZEUSPAY] switching user from android/ios to zeus -> " . json_encode($data), "debug");
3224                }
3225
3226                $discountOption = isset($ptPaymentParams['discountOption']) ? $ptPaymentParams['discountOption'] : [];
3227                $zeroStudentDiscount = false;
3228
3229                // set premium_coin_purchase_flg to 0 and set first charge date
3230                if (
3231                    $discountOption &&
3232                    $formType == Configure::read('payment_lite_credit_monthly_payment') && 
3233                    isset($ptPaymentParams['userRegister']) &&
3234                    $ptPaymentParams['userRegister']
3235                ) {
3236                    $saveUserArr['User']['premium_coin_purchase_flg'] = 0;
3237                    $saveUserArr['User']['first_charge_date'] = date('Y-m-d H:i:s');
3238                }
3239
3240                # update the user information
3241                $this->User->validate = array();
3242                if (!$read = $this->User->read(null, $userData['User']['id'])) {
3243                    $this->log(__METHOD__ . ' User id does not exist. ' . json_encode($userData) . ' -- ' . json_encode($data), $logFileName);
3244                    $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'User id does not exist', $data, $userData);
3245                    return ;
3246                }
3247                $currency_before = $userData['User']['currency_code'];
3248                $plan_before = $userData['User']['payment_plan_id'];
3249
3250                $famRegist = false;
3251                // NC-4673: update family parent_id, memo and monthly_payment
3252
3253
3254                if (
3255                    in_array($formType, Configure::read('family_plan_form_types'))
3256                ) {
3257                    // if parent_id is empty
3258                    if (empty($read['User']['parent_id'])) {
3259                        $saveUserArr['User']['parent_id'] = $data['sendid'];
3260                        $saveUserArr['User']['memo'] = date('Y/m/d H:i:s')." Family plan[User]: family registration \n".$read['User']['memo'];
3261                        $famRegist = true;
3262
3263                
3264                        if (empty($read['User']['currency_code'])) {
3265                            $saveUserArr['User']['currency_code'] = $currencyCode;
3266                        }
3267                    }
3268                }
3269
3270                // - NJ-18780 : add next charge date for upgrade and downgrade plan
3271                if (
3272                    (
3273                        $formType == Configure::read('payment_lite_plan_downgrade') || 
3274                        $formType == Configure::read('payment_lite_plan_upgrade')
3275                    )
3276                    && (isset($ptPaymentParams['changePlanChargeFlg']) && $ptPaymentParams['changePlanChargeFlg'])
3277                ) {
3278                    $nextChargeDate = $this->User->getNextChargeDate();
3279                    $saveUserArr['User']['next_charge_date'] = $nextChargeDate;
3280                }
3281
3282                //- chocotto credit auth remove the campaign code
3283                if ($formType == Configure::read('payment_credit_chocotto_free')) {
3284                    $saveUserArr['User']['campaign_id'] = NULL;
3285                }
3286
3287
3288                // campaign master trigger 2
3289                if (
3290                    strtoupper($data['result']) == 'OK' &&
3291                    $formType == Configure::read('payment_credit_monthly_payment') && 
3292                    $userData['User']['payment_plan_id'] == Configure::read('payment_plans.free_trial')
3293                ) {
3294                    UsersPointTable::giveBonusCoins(['userId' => $userId, 'triggerNo' => 2]);
3295                }
3296                // - NJ-36141: whenever status changed, reset Chocotto Daily Lesson Time
3297                $this->UsersDetail->chocottoCampUserDetails($userData['User']['id'], true);
3298                $this->User->set($saveUserArr);
3299                if (!$this->User->save()) {
3300                    $this->log(__METHOD__ . ' Failed update user data. ' . json_encode($saveUserArr) . ' -- ' . json_encode($data), $logFileName);
3301                    $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed update user data', $data, $saveUserArr);
3302                    return ;
3303                }
3304
3305                // check if payment plan upgrade
3306                if ($formType == Configure::read('payment_lite_plan_upgrade')) {
3307                    // get user zero student discount term
3308                    $discountOptionTermData = $this->UserDiscountOptionsTerm->getTerm([
3309                        'user_id' =>  $userId,
3310                        'discount_option_id' => Configure::read('discount_option.zero_student.plan_id'),
3311                        'status' => 1
3312                    ]);
3313
3314                    // stop zero student discount
3315                    if ($discountOptionTermData) {
3316                        // open tunnel
3317                        myTools::initializeApiTunnel(['DiscountOptionController']);
3318
3319                        // initialize controller
3320                        $doc = new DiscountOptionController();
3321
3322                        $docParams = [
3323                            'discountOptionId' => $discountOptionTermData['discount_option_id'],
3324                            'discountOptionPriceId' => $discountOptionTermData['discount_option_price_id'],
3325                            'termId' => $discountOptionTermData['discount_option_term_id'],
3326                            'cancellationFee' => 0,
3327                            'cancellationType' => Configure::read('discount_option.dosh_type.plan_change'),
3328                            'userData' => $userData['User'],
3329                            'fromController' => $this->request->params['controller'],
3330                            'fromAction' => $this->request->params['action'],
3331                            'doshStatus' => Configure::read('discount_option.dosh_status.midterm_cancellation')
3332                        ];
3333
3334                        // set data
3335                        $doc->params = $docParams;
3336
3337                        if (!$doc->stopDiscountOption()) {
3338                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to stop discount option. ', $docParams);
3339                            return ;
3340                        }
3341                    }
3342                }
3343
3344                // if user plan has discount option
3345                if ($discountOption) {
3346                    $contractStart = $formType != Configure::read('payment_credit_authentication') ? date('Y-m-d 00:00:00') : (isset($nextChargeDate) ? $nextChargeDate : $this->User->getFirstNextChargeDate());
3347                    if (
3348                        (
3349                            $discountOption['discount_option_id'] == Configure::read('discount_option.zero_student.plan_id') &&
3350                            $formType == Configure::read('payment_lite_credit_monthly_payment') && 
3351                            isset($ptPaymentParams['userRegister']) &&
3352                            $ptPaymentParams['userRegister']
3353                        ) ||
3354                        in_array(
3355                            $formType,
3356                            [
3357                                Configure::read('payment_credit_authentication'),
3358                                Configure::read('payment_credit_force_charge'),
3359                                Configure::read('payment_lite_plan_upgrade')
3360                            ]
3361                        )
3362                    ) {
3363                        // set amount to 0 if card auth
3364                        if ($formType == Configure::read('payment_credit_authentication')) {
3365                            $discountOption['amount'] = 0;
3366                        }
3367
3368                        // set data for user discount option term
3369                        $udotData = [
3370                            'userId' => $userId,
3371                            'discountOptionId' => $discountOption['discount_option_id'],
3372                            'discountOptionPriceId' => $discountOption['discount_option_price_id'],
3373                            'contractStart' => $contractStart,
3374                            'logFileName' => $logFileName,
3375                            'paymentId' => $paymentSaveID,
3376                            'discountAmount' => $discountOption['amount'],
3377                            'doshEvent' => isset($discountOption['dosh_event']) ? $discountOption['dosh_event'] : null,
3378                            'currencyCode' => $currencyCode,
3379                            'doshStatus' => isset($discountOption['dosh_status']) ? $discountOption['dosh_status'] : null,
3380                            'formType' => $formType,
3381                            'userRegister' => isset($ptPaymentParams['userRegister']) ? true : false
3382                        ];
3383
3384                        if (isset($discountOption['dosh_type'])) {
3385                            $udotData['doshType'] = $discountOption['dosh_type'];
3386                        }
3387
3388                        if (
3389                            $discountOption['discount_option_id'] == Configure::read('discount_option.zero_student.plan_id') &&
3390                            $formType == Configure::read('payment_lite_credit_monthly_payment')
3391                        ) {
3392                            $zeroStudentDiscount = true;
3393                        }
3394
3395                        // create user discount option term
3396                        if (!$this->UserDiscountOptionsTerm->createTerm($udotData)) {
3397                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to create user discount option term. ', $udotData);
3398                            return ;
3399                        }
3400
3401                        // check if has uploaded data for zero student document(s)
3402                        if (isset($discountOption['application_form_app_image_url'])) {
3403                            $applicationData = [
3404                                'user_id' => $userId,
3405                                'image_url' => $discountOption['application_form_app_image_url']
3406                            ];
3407            
3408                            // save document url
3409                            if (!$this->StudentDiscountApplicationForm->saveApplicationForm($applicationData)) {
3410                                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save zero student application form. ', $applicationData);
3411                                return ;
3412                            }
3413
3414                            $udData = [
3415                                'user_id' => $userId,
3416                                'individual_card_fail_flg'    => 0,
3417                                'show_zero_student_discount_option_flg' => 1
3418                            ];
3419
3420                            $this->UsersDetail->clear();
3421                            $this->UsersDetail->set($udData);
3422                            $this->UsersDetail->validate = [];
3423                            if (!$this->UsersDetail->save()) {
3424                                $this->log(__METHOD__ . ' Failed insert users detail data. ' . json_encode($udData) . ' -- ' . json_encode($data), $logFileName);
3425                                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to insert users detail data. ', $udData);
3426                                return ;
3427                            }
3428
3429                            $slackParams = [
3430                                'userId' => $userId,
3431                                'nickname' => $userData['User']['nickname'],
3432                                'nextChargeDate' => $this->User->getNextChargeDate(),
3433                                'applicationCnt' => 1,
3434                                'appFormUrl' => $discountOption['application_form_app_image_url']
3435                            ];
3436
3437                            // send slack
3438                            StudentDiscountApplicationFormTable::sendSlackStudentDiscountInfo($slackParams);
3439                        }
3440                    } elseif (in_array($formType, [Configure::read('payment_credit_monthly_payment'), Configure::read('payment_credit_retry')])) {
3441                        $discountOption += [
3442                            'contract_start' => $contractStart,
3443                            'currency_code' => $currencyCode,
3444                            'payment_id' => $paymentSaveID,
3445                            'dosh_settlement_status' => 1, // success
3446                            'form_type' => $formType
3447                        ];
3448
3449                        if (!$this->UserDiscountOptionsTerm->processMonthlyDiscountOption($discountOption)) {
3450                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to process monthly discount option. ', $discountOption);
3451                            return ;
3452                        }
3453                    }
3454
3455                    if (
3456                        (
3457                            in_array(
3458                                $formType,
3459                                [
3460                                    Configure::read('payment_credit_authentication'),
3461                                    Configure::read('payment_credit_force_charge'),
3462                                    Configure::read('payment_lite_plan_upgrade')
3463                                ]
3464                            ) ||
3465                            (
3466                                $discountOption['discount_option_id'] == Configure::read('discount_option.zero_student.plan_id') &&
3467                                $formType == Configure::read('payment_lite_credit_monthly_payment') && 
3468                                isset($ptPaymentParams['userRegister']) &&
3469                                $ptPaymentParams['userRegister']
3470                            )
3471                        ) &&
3472                        isset($discountOption['option_after_name']) &&
3473                        isset($discountOption['option_type'])
3474                    ) {
3475                        $adoLogParams = [
3476                            'user_id' => $userId,
3477                            'platform' => $platform,
3478                            'status' => 1, // subscribe
3479                            'controller_name' => $this->request->params['controller'],
3480                            'action_name' => $this->request->params['action'],
3481                            'user_type' => 0, // normal user
3482                            'option_before' => '',
3483                            'option_after' => 1,
3484                            'option_before_name' => isset($discountOption['option_before_name']) ? $discountOption['option_before_name'] : '',
3485                            'option_after_name' => $discountOption['option_after_name'],
3486                            'option_type' => $discountOption['option_type'],
3487                            'payment_plan_id' => $paymentPlanId
3488                        ];
3489
3490                        if (!$this->UserOptionChangeLog->saveOptionChangeLog($adoLogParams)) {
3491                            $this->log(__METHOD__ . ' Failed to update option change. ' . json_encode($adoLogParams), $logFileName);
3492                            $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'Failed to update user data', $adoLogParams);
3493                            return ;
3494                        }
3495                    }
3496                }
3497
3498                # NJ-27262 chocotto plan charge or 
3499                if (in_array(
3500                    $formType, [
3501                        Configure::read('payment_credit_chocotto_monthly_payment'),
3502                        Configure::read('payment_credit_chocotto_retry')
3503                    ]
3504                )) {
3505                    //- confiscate lite points
3506                    UserTable::changePlanProcess(['user_id' => $userId]);
3507
3508                    //- update users if has options
3509                    if (
3510                        !empty($userData['User']['native_option']) ||
3511                        !empty($userData['User']['callan_option'])
3512                    ) {
3513                        $_userUpdate = array('id' => $userData['User']['id']);
3514
3515                        //- native options
3516                        if (!empty($userData['User']['native_option'])) {
3517                            $_userUpdate['native_option'] = 0;
3518                            $_userUpdate['native_option_cancellation_time'] = date('Y-m-d H:i:s');
3519                        }
3520
3521                        //- callan options
3522                        if (!empty($userData['User']['callan_option'])
3523                        ) {
3524                            $_userUpdate['callan_option'] = 0;
3525                            $_userUpdate['callan_option_cancellation_time'] = date('Y-m-d H:i:s');
3526                        }
3527                        $this->User->set($_userUpdate);
3528                        if (!$this->User->save()) {
3529                            $this->log(__METHOD__ . ' Failed to update user data. ' . json_encode($_userUpdate), $logFileName);
3530                            $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed to update user data', $_userUpdate);
3531                        }
3532                    }
3533                }
3534
3535                # NJ-18780 : changed plan to liteplan
3536                if (
3537                    $formType == Configure::read('payment_lite_plan_downgrade') || 
3538                    $formType == Configure::read('payment_lite_plan_upgrade')
3539                ) {
3540                    $this->User->openDBReplica();
3541                    $_currentUser = $this->User->find('first', array(
3542                        'fields' => array('User.parent_id', 'User.currency_code', 'User.payment_plan_id','User.memo','User.native_option','User.callan_option','next_charge_date'),
3543                        'conditions' => array('User.id' => $userData['User']['id']),
3544                        'recursive' => -1
3545                    ));
3546                        $this->User->closeDBReplica();
3547
3548                    $_memoCoins = 'SC and PC';
3549                    $_updateMemo = '';
3550                    $litenativeOptionBefore = $litenativeOptionAfter = $_currentUser['User']['native_option'];
3551                       $litecallanOptionBefore = $litecallanOptionAfter = $_currentUser['User']['callan_option'];
3552                       $isliteNativeOptionChange = $isliteCallanOptionChange = false;
3553
3554                       $liteUserUpdateArr = array();
3555                       $_dateNow = date("Y-m-d H:i:s");
3556
3557                    // - turn off native option if it is on
3558                    if ((int) $litenativeOptionBefore == 1) {
3559                        $liteUserUpdateArr['native_option'] = 0; // turn off
3560                        $liteUserUpdateArr['native_option_cancellation_time'] = $dateNow;
3561                        $litenativeOptionAfter = 0;
3562                        $isliteNativeOptionChange = true;
3563
3564                        // set memo
3565                        $_updateMemo = $_updateMemo. "\n{$_dateNow} \nChanged by due Selected Light Plan / Native Unlimited option OFF";
3566                    }
3567
3568                    // - turn off callan option if it is on
3569                    if ((int) $litecallanOptionBefore == 1) {
3570                        $liteUserUpdateArr['callan_option'] = 0; // turn off
3571                        $liteUserUpdateArr['callan_option_cancellation_time'] = $dateNow;
3572                        $litecallanOptionAfter = 0;
3573                        $isliteCallanOptionChange = true;
3574
3575                        $_updateMemo = $_updateMemo. "\n{$_dateNow} \nChanged by due Selected Light Plan / Callan Unlimited option OFF";
3576                    }
3577
3578                    // - changing to lite plan
3579                    if ($formType == Configure::read('payment_lite_plan_downgrade')) {
3580                    
3581                        // - confiscate all mc coins
3582                        $_monthlyPoints = $this->UsersPoint->getCurrentUserMCPoint($userData['User']['id']); 
3583                        $_memoCoins = "MC";
3584
3585                        if ((int) $_monthlyPoints > 0) {
3586                            $confiscateParams = array(
3587                                'userId' => $userData['User']['id'],
3588                                'point' => $_monthlyPoints,
3589                                'kbn' => 18, 
3590                                'coinType' => 3
3591                            );
3592
3593
3594                            // rollback if confiscating points failed
3595                            if (!$confiscateCoinFlg = $this->UsersPoint->confiscateUserLitePoints($confiscateParams)) {
3596                                $this->log(__METHOD__ . ' Failed to confiscate points. --> ' . json_encode($confiscateParams) . ' -- ' . json_encode($data), $logFileName);
3597                                        
3598                                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userData['User']['id'], 'Failed to confiscate points.', $userData);
3599                                return ;
3600                            }
3601
3602                            $_updateMemo = $_updateMemo . "\n {$_dateNow} (Previous Coins ({$_memoCoins})【Confiscated】 : {$_monthlyPoints}. )";
3603                        }
3604
3605                        $doneConfiscatePoints = ClassRegistry::init('UsersPointHistory')->confiscateUserLitePointsCoinBox($userData['User']['id']);
3606
3607                        $nextChargeDateLite = $this->User->getNextChargeDate();
3608
3609                        // - give lite bonus coins
3610                        $_pointParams = array(
3611                            'userId' => $userData['User']['id'],
3612                            'point' => Configure::read('lite_plan_monthly_coin'),
3613                            'kbn' => Configure::read('lite_plan_bonus_kbn'), // 
3614                            'kbnType' => 1, // add coin
3615                            'coinType' => 3, // mc coin
3616                            'dateExpiration' => $nextChargeDateLite,
3617                            'coinFailMessage' => Configure::read('coin.failed.membership')
3618                        );
3619
3620                        // rollback if adding  points failed
3621                        if (!$_addCoinsFlg = $this->UsersPoint->performPointTransaction($_pointParams)) {
3622                            $this->log(__METHOD__ . ' Failed to give points. --> ' . json_encode($confiscateParams) . ' -- ' . json_encode($data), $logFileName);
3623                                    
3624                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to give points.', $data);
3625                            return ;
3626                        }
3627
3628                        $_coins = Configure::read('lite_plan_monthly_coin');
3629                        $updateMemo = $updateMemo . "\n {$_dateNow} | Light Plan Bonus Coins (MC): {$_coins}";
3630                    }
3631
3632                    // - changing from premium to lite plan
3633                    if ($formType == Configure::read('payment_lite_plan_upgrade')) {
3634                        // - confiscate all held coins
3635                        $_monthlyPoints = $this->UsersPoint->getCurrentUserMCPoint($userData['User']['id']); //  mc coins
3636
3637                        $_memoCoins = "MC";
3638
3639                        if ((int) $_monthlyPoints > 0) {
3640                            $confiscateParams = array(
3641                                'userId' => $userData['User']['id'],
3642                                'point' => $_monthlyPoints,
3643                                'kbn' => 18, 
3644                                'coinType' => 3
3645                            );
3646
3647
3648                            // rollback if confiscating points failed
3649                            if (!$confiscateCoinFlg = $this->UsersPoint->confiscateUserLitePoints($confiscateParams)) {
3650                                $this->log(__METHOD__ . ' Failed to confiscate points. --> ' . json_encode($confiscateParams) . ' -- ' . json_encode($data), $logFileName);
3651                                        
3652                                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userData['User']['id'], 'Failed to confiscate points.', $userData);
3653                                return ;
3654                            }
3655
3656                            $_updateMemo = $_updateMemo . "\n {$_dateNow} (Previous Coins ({$_memoCoins})【Confiscated】 : {$_monthlyPoints}. )";
3657                        }
3658
3659                        $_doneConfiscatePoints = ClassRegistry::init('UsersPointHistory')->confiscateUserLitePointsCoinBox($userData['User']['id']);
3660                    }
3661
3662                    #update the user information memo
3663                    if (empty($_updateMemo)) {
3664
3665                        $_updateMemo = $_updateMemo . "\n" . $_currentUser['User']['memo'];
3666                     
3667                        $_userUpdate = array(
3668                            'id' => $userData['User']['id'],
3669                            'memo' => $_updateMemo
3670                        );
3671
3672                        $this->User->set($_userUpdate);
3673                        if (!$this->User->save()) {
3674                            $this->log(__METHOD__ . ' Failed to update user data. ' . json_encode($_userUpdate), $logFileName);
3675                            $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed to update user data', $_userUpdate);
3676                            return ;
3677                        }
3678                    }
3679
3680                    // - update the user information
3681                    if ($liteUserUpdateArr) {
3682                        $liteUserUpdateArr['id'] = $userData['User']['id'];
3683
3684                        // - set user 
3685                        $this->User->set($liteUserUpdateArr);
3686
3687                        if (!$this->User->save()) {
3688                            $this->log(__METHOD__ . ' Failed to update user data. ' . json_encode($liteUserUpdateArr), $logFileName);
3689                            $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed to update user data', $_userUpdate);
3690                            return ;
3691                        }
3692                    }
3693
3694                    # add log if there is change on native option
3695                    if ($isliteNativeOptionChange) {
3696                        $optionLogParams = array(
3697                            'user_id' => $userData['User']['id'],
3698                            'platform' => Configure::read('platform.pclp'),
3699                            'status' => 3,//set to unsubscribe
3700                            'controller_name' => $this->request->params['controller'],
3701                            'action_name' => $this->request->params['action'],
3702                            'user_type' => 0, // user
3703                            'option_before' => 1,
3704                            'option_after' => '',
3705                            'option_before_name' => 'Native Unlimited Option',
3706                            'option_after_name' => '',
3707                            'option_type' => 1,
3708                            'payment_plan_id' => $paymentPlanId
3709                        );
3710
3711                        $_saveLog = ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
3712
3713                        if (!$_saveLog) {
3714                            $this->log(__METHOD__ . ' Failed to update option change. ' . json_encode($optionLogParams), $logFileName);
3715                            $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed to update user data', $optionLogParams);
3716                            return ;
3717                        }
3718                    }
3719
3720                    # add log if change on callan option 
3721                    if ($isliteCallanOptionChange) {
3722
3723                        $optionLogParams = array(
3724                            'user_id' => $userId,
3725                            'platform' => Configure::read('platform.pclp'),
3726                            'status' => 3,//unsubscribe
3727                            'controller_name' => $this->request->params['controller'],
3728                            'action_name' => $this->request->params['action'],
3729                            'user_type' => 0, // user
3730                            'option_before' => 1,
3731                            'option_after' => '',
3732                            'option_before_name' => 'Callan Unlimited Option',
3733                            'option_after_name' => '',
3734                            'option_type' => 2,
3735                            'payment_plan_id' => $paymentPlanId
3736                        );
3737
3738                        $_saveLog = ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
3739
3740                        // rollback if confiscating points failed
3741                        if (!$_saveLog) {
3742                            $this->log(__METHOD__ . ' Failed to save user option change log. --> ' . json_encode($optionLogParams) . ' -- ' . json_encode($data), $logFileName);
3743                                    
3744                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save option log.', $optionLogParams);
3745                            return ;
3746                        }
3747                    }
3748                }
3749                
3750
3751                // NC-7459 check previus user status, add coinbox challenge
3752                if (
3753                    isset($read['User']['payment_plan_id'])
3754                    && $read['User']['payment_plan_id'] == Configure::read('payment_plans.complimentary_plan')
3755                    && isset($read['User']['complimentary_code'])
3756                ) {
3757
3758                    // get complimentary coin award
3759                    $coinAward = $this->ComplimentaryCode->find('first', array(
3760                        'fields' => array('coin_award'),
3761                        'conditions' => array(
3762                            'ComplimentaryCode.code' => $read['User']['complimentary_code'],
3763                            'ComplimentaryCode.template_type !=' => 0 // // Free trial
3764                        )
3765                    ));
3766
3767                    if (
3768                        isset($coinAward['ComplimentaryCode']['coin_award'])
3769                        && $coinAward['ComplimentaryCode']['coin_award']
3770                    ) { // @TODO use common @note did not use CoinBox->addCoinReward because it will not succeed for unknown reason.
3771                        $coinboxSet = array(
3772                            'status' => 1,
3773                            'user_id' => $userData['User']['id'],
3774                            'teacher_id' => null,
3775                            'coin_event_id' => Configure::read('coin_box_event.complimentary'),
3776                            'coin' => $coinAward['ComplimentaryCode']['coin_award'],
3777                            'lesson_id' => NULL,
3778                            'expiration_date' => date('Y-m-d 23:59:59', strtotime('+59 days'))
3779                        );
3780                        $this->CoinBox->create();
3781                        $this->CoinBox->set($coinboxSet);
3782                        if (!$this->CoinBox->save()) {
3783                            CakeLog::debug('[debug_payment_proceed] complimentary coin award : ' . json_encode($saveUserArr));
3784                            $this->log(__METHOD__ . ' Failed adding complimentary coin award . ' . json_encode($saveUserArr) . ' -- ' . json_encode($data) . ' -- ' . json_encode($coinAward), $logFileName);
3785                            $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed adding complimentary coin award', $data, $coinboxSet);
3786                            return ;
3787                        }
3788                    }
3789                }
3790                
3791                $memKey = 'family_reactivation_' . $data['sendid'] . '_' . $familyId;
3792                $familyReactivation = $this->memcache->get($memKey);
3793                // NC-3754 : add memo for reactivation parent user.
3794                if ($formType == Configure::read('payment_credit_family_monthly_payment') && !empty($read['User']['parent_id']) && $familyReactivation) {
3795                    $famRegist = false;
3796                    // delete memcache
3797                    $this->memcache->delete($memKey);
3798                    $this->User->clear();
3799                    if (!$userRead = $this->User->read(array('memo'), $data['sendid'])) {
3800                        $this->log(__METHOD__ . ' User id does not exist. ' . json_encode($data), $logFileName);
3801                        $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'User id does not exist', $data);
3802                        return ;
3803                    }
3804
3805                    $this->User->set(array('memo' => date('Y/m/d H:i:s')." Family plan[User]: family id: " . $userData['User']['id'] . " reactivation \n" . $userRead['User']['memo']));
3806                    $this->User->validate = false;
3807                    if (!$this->User->save()) {
3808                        $this->log(__METHOD__ . ' Failed update user data. ' . json_encode($userRead) . ' -- ' . json_encode($data), $logFileName);
3809                        $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed update user data', $data, $userRead);
3810                        return ;
3811                    }
3812                }
3813
3814                // NC-3754 
3815                // Proccess Family Plan
3816                if($famRegist && !$familyReactivation) {
3817                    // @param:  parent id. for memcache key.
3818                    $famPlanRes = $this->FamilyPlanList->processFamPlan($data['sendid'], $familyId, $data['sendpoint']);
3819                    if ($famPlanRes != "[OK]") {
3820                        $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], $famPlanRes, $data);
3821                        return;
3822                    }
3823                }
3824
3825                // check if membership status was change
3826                if (isset($ptPaymentParams['statusBefore']) && isset($ptPaymentParams['statusAfter']) && isset($ptPaymentParams['platform'])) {
3827                    $currentUser = $this->User->find('first', array(
3828                        'fields' => array(
3829                            'User.parent_id', 
3830                            'User.currency_code', 
3831                            'User.payment_plan_id',
3832                            'User.native_option', 
3833                            'User.callan_option'
3834                        ),
3835                        'conditions' => array('User.id' => $userId),
3836                        'recursive' => -1
3837                    ));
3838                    $parentId = $currentUser['User']['parent_id'];
3839                    $is_cron = 0;
3840                    if (php_sapi_name() == 'cli' || $ptPaymentParams['logFileName'] == 'retry_monthly_payment'){
3841                        $is_cron = 1;
3842                    } 
3843                       $currency_after = $currentUser['User']['currency_code'];
3844                       $plan_after = $currentUser['User']['payment_plan_id'];
3845
3846                    $usclData = array(
3847                        'user_id' => $userId,
3848                        'platform' => $ptPaymentParams['platform'] ?? '',
3849                        'card_company_before' => $read['User']['card_company'],
3850                        'status_before' => $ptPaymentParams['statusBefore'],
3851                        'status_after' => $ptPaymentParams['statusAfter'],
3852                        'controller_name' => $this->request->params['controller'],
3853                        'action_name' => $this->request->params['action'],
3854                        'parent_id' => $parentId,
3855                        'is_cron' => $is_cron,
3856                        'currency_before' => $currency_before,
3857                        'currency_after' => $currency_after,
3858                        'payment_plan_id_before' => $plan_before,
3859                        'payment_plan_id_after' => $plan_after,
3860                        'default_appreciation_flg' => $appreciationFlg,
3861                        'default_appreciation_amount' => $tipAmount
3862                    );
3863                    // save user change membership status
3864                    if (!$this->UserStatusChangeLog->saveLog($usclData)) {
3865                        $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'Unable to update status change log', $usclData);
3866                        return;
3867                    }
3868
3869                    //- Update users if changed to a light plan and has options
3870                    if (in_array($plan_after, Configure::read('lite_payment_plans'))) {
3871                        $optionsToUpdate = [];
3872
3873                        //- Check and prepare the options to update
3874                        if (!empty($currentUser['User']['native_option'])) {
3875                            $optionsToUpdate['native_option'] = 0;
3876                            $optionsToUpdate['native_option_cancellation_time'] = date('Y-m-d H:i:s');
3877                        }
3878
3879                        if (!empty($currentUser['User']['callan_option'])) {
3880                            $optionsToUpdate['callan_option'] = 0;
3881                            $optionsToUpdate['callan_option_cancellation_time'] = date('Y-m-d H:i:s');
3882                        }
3883
3884                        //- If there are options to update, proceed
3885                        if (!empty($optionsToUpdate)) {
3886                            $optionsToUpdate['id'] = $userId;
3887                            $this->User->set($optionsToUpdate);
3888                            
3889                            if (!$this->User->save()) {
3890                                $this->log(__METHOD__ . ' Failed to update user data. ' . json_encode($optionsToUpdate), $logFileName);
3891                                $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'Failed to update user data', $optionsToUpdate);
3892                                return;
3893                            }
3894                        }
3895                    }
3896                }
3897
3898                # check if user is temporary
3899                if (
3900                    ($userData['User']['status'] == 0 && $formType == Configure::read('payment_credit_authentication')) || 
3901                    ($userData['User']['status'] == 0 && $formType == Configure::read('payment_lite_credit_free') ) ||
3902                    ($userData['User']['status'] == 0 && $formType == Configure::read('payment_credit_chocotto_free') )
3903                ) {
3904                    # update user's status after step 4
3905                    $this->User->validate = array();
3906                    if (!$this->User->read(null, $userData['User']['id'])) {
3907                        $this->log(__METHOD__ . ' User id does not exist. ' . json_encode($userData), $logFileName);
3908                        $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'User id does not exist', $userData);
3909                        return ;
3910                    }
3911                    $this->User->set('status', 1);
3912                    if (!$this->User->save()) {
3913                        $this->log(__METHOD__ . ' Failed update user status to 1. ' . json_encode($data), $logFileName);
3914                        $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed update user status to 1', $data);
3915                        return ;
3916                    }
3917                }
3918
3919                // NC-7779 : check if user has chivox monthly test taken for the current month, and monthly_speaking_attended_flg ON,
3920                // turn Off the flag if users has not yet taken the exam for the current month.
3921                // @TODO check query
3922                if (
3923                    isset($userData['User']['monthly_speaking_attended_flg']) && isset($userData['User']['monthly_speaking_business_attended_flg'])
3924                    && ($userData['User']['monthly_speaking_attended_flg'] == 1 || $userData['User']['monthly_speaking_business_attended_flg'] == 1)
3925                ) {
3926
3927                    // check chivox monthly
3928                    $paymentPlanIdsForChivoxMonthly = Configure::read('chivox.monthly.user_payment_plan_cantake_exam');
3929                    if (in_array($paymentPlanId, $paymentPlanIdsForChivoxMonthly)) {
3930
3931                        // load model
3932                        $this->loadModel("UsersChivoxMonthlyTest");
3933                        $userTestMonthFlagParams['user_id'] = $userData['User']['id'];
3934                        $userTestMonthFlag = $this->UsersChivoxMonthlyTest->checkUserCurrentMonthExam($userTestMonthFlagParams);
3935
3936                        $monthly_speaking_attended_flg = Configure::read('chivox.test_data_test_type.daily'); // test_type daily speaking 0
3937                        $monthly_speaking_business_attended_flg = Configure::read('chivox.test_data_test_type.business'); // test_type business 1
3938                        $fieldsToUpdate = array();
3939
3940                        // if user hat not yet taken the exam for current month
3941                        if (!in_array($monthly_speaking_attended_flg, $userTestMonthFlag)) {
3942                            $fieldsToUpdate['monthly_speaking_attended_flg'] = 0;
3943                        }
3944                        if (!in_array($monthly_speaking_business_attended_flg, $userTestMonthFlag)) {
3945                            $fieldsToUpdate['monthly_speaking_business_attended_flg'] = 0;
3946                        }
3947
3948                        if ($fieldsToUpdate) {
3949                            $this->User->validate = array();
3950                            if (!$this->User->read(null, $userData['User']['id'])) {
3951                                $this->log(__METHOD__ . ' [NC-7779] User id does not exist. ' . json_encode($userData), $logFileName);
3952                                $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'User id does not exist', $userData);
3953                                return ;
3954                            }
3955                            $this->User->set($fieldsToUpdate);
3956                            if (!$this->User->save()) {
3957                                $this->log(__METHOD__ . ' [NC-7779] Failed update user monthly_speaking_attended_flg or monthly_speaking_business_attended_flg to 0. ' . json_encode($data), $logFileName);
3958                                $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed update user monthly_speaking_attended_flg to 0', $data);
3959                                return ;
3960                            }
3961                        }
3962                    }
3963                }
3964            }
3965
3966            $annualDiscountOption = isset($ptPaymentParams['annualDiscountOption']) ? $ptPaymentParams['annualDiscountOption'] : [];
3967            // if user cancel annual discount option
3968            if (
3969                $annualDiscountOption &&
3970                isset($annualDiscountOption['cancellation_fee']) &&
3971                $formType == Configure::read('payment_halfway_termination_of_annual_discount_option')
3972            ) {
3973                $doshData = [
3974                    'user_id' => $userId,
3975                    'discount_option_term_id' => $annualDiscountOption['discount_option_term_id'],
3976                    'discount_option_id' => $annualDiscountOption['discount_option_id'],
3977                    'discount_option_price_id' => $annualDiscountOption['discount_option_price_id'],
3978                    'payment_id' => $paymentSaveID,
3979                    'event' => $annualDiscountOption['dosh_event'],
3980                    'amount' => $annualDiscountOption['cancellation_fee'],
3981                    'currency_code' => $currencyCode,
3982                    'type' => $annualDiscountOption['dosh_type'],
3983                    'status' => $annualDiscountOption['dosh_status'],
3984                    'settlement_status' => 1 // success
3985                ];
3986
3987                // create discount option settlement history
3988                if (!$res = $this->DiscountOptionsSettlementHistory->createHistory($doshData)) {
3989                    $this->log(__METHOD__ . ' Failed to create discount option settlement history. ' . json_encode($doshData), $logFileName);
3990                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to create discount option settlement history. ', $doshData);
3991                    return ;
3992                }
3993
3994                // stop user annual discount option term
3995                if (!$this->UserDiscountOptionsTerm->stopTerm(['userId' => $userId])) {
3996                    $this->log(__METHOD__ . ' Failed to stop annual discount option term. ' . json_encode(['userId' => $userId]), $logFileName);
3997                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to stop annual discount option term.', ['userId' => $userId]);
3998                    return ;
3999                }
4000
4001                // update user memo
4002                $memo = date('Y/m/d H:i') . " 年間割引オプション解約\n" . $userData['User']['memo'];
4003                if (!$this->User->updateUserById(['userData' => ['memo' => $memo], 'id' => $userId])) {
4004                    $this->log(__METHOD__ . ' Failed to update user memo. ' . json_encode($memo) . ' id: ' . json_encode($userId), $logFileName);
4005                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to stop annual discount option term.', [$memo]);
4006                    return ;
4007                }
4008                
4009                $adoLogParams = [
4010                    'user_id' => $userId,
4011                    'platform' => $platform,
4012                    'status' => 1, // subscribe
4013                    'controller_name' => $this->request->params['controller'],
4014                    'action_name' => $this->request->params['action'],
4015                    'user_type' => 0, // normal user
4016                    'option_before' => 1,
4017                    'option_after' => '',
4018                    'option_before_name' => 'Annual Discount Option',
4019                    'option_after_name' => '',
4020                    'option_type' => 3, // annual discount option
4021                    'payment_plan_id' => $paymentPlanId
4022                ];
4023
4024                if (!$this->UserOptionChangeLog->saveOptionChangeLog($adoLogParams)) {
4025                    $this->log(__METHOD__ . ' Failed to update option change. ' . json_encode($adoLogParams), $logFileName);
4026                    $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'Failed to update user data', $adoLogParams);
4027                    return ;
4028                }
4029            }
4030
4031            // if payment was saved, and form type belongs to textbook purchase,
4032            // update textbook_sales table, insert payment_id
4033            if ($formType == Configure::read('payment_credit_textbook_purchase')) {
4034                // set textbook sales info
4035                $textbookSales = $this->TextbookSale->find('first', array(
4036                    'conditions' => array(
4037                        'TextbookSale.sales_code' => $ptPassword
4038                    ),
4039                    'recursive' => -1
4040                ));
4041                
4042                // if has textbook sales, update payment_id
4043                if ($textbookSales) {
4044                    $this->TextbookSale->clear();
4045                    if (!$this->TextbookSale->read(null, $textbookSales['TextbookSale']['id'])) {
4046                        $this->log(__METHOD__ . ' Textbook sales id does not exist. ' . json_encode($textbookSales), $logFileName);
4047                        $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'Textbook sales id does not exist', $textbookSales);
4048                        return ;
4049                    }
4050                    $this->TextbookSale->set('payment_id', $this->Payment->id);
4051                    $this->TextbookSale->set('payment_status', 1);
4052                    if (!$this->TextbookSale->save()) {
4053                        $this->log(__METHOD__ . ' Failed update textbook sales payment status to 1. ' . json_encode($textbookSales), $logFileName);
4054                        $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'Failed update textbook sales payment status to 1', $textbookSales);
4055                        return ;
4056                    }
4057                }
4058            }
4059
4060            // If Chocotto user, set active_flg to 0
4061            // check if has complimentary code, set active_flg to 0
4062            if (in_array($formType, array(
4063                    Configure::read('payment_credit_chocotto_free'),
4064                    Configure::read('payment_credit_chocotto_monthly_payment'),
4065                    Configure::read('payment_credit_chocotto_force_charge')
4066                )) && $compCodeData = $this->CompCodeUsage->ifHasActiveComplimentaryCode($userData['User']['id'])
4067            ) {
4068                $this->CompCodeUsage->updateAll(
4069                    array(
4070                        'active_flg' => 0
4071                    ),
4072                    array(
4073                        'user_id' => $userData['User']['id'],
4074                        'active_flg' => 1,
4075                        'code' => $compCodeData['CompCodeUsage']['code']
4076                    )
4077                );
4078            }
4079
4080            // [ZEUS] check if receivable payment sent was either
4081            // receivable payment, monthly payment, force settlement, or retry payment
4082            // if yes, set receivable payments to "received"
4083            if (
4084                in_array($formType, array(
4085                    Configure::read('payment_credit_appreciation_receivable'),
4086                    Configure::read('payment_credit_receivable'),
4087                    Configure::read('payment_credit_monthly_payment'),
4088                    Configure::read('payment_credit_force_charge'),
4089                    Configure::read('payment_credit_retry'),
4090                    Configure::read('payment_credit_family_monthly_payment'),
4091                    Configure::read('payment_lite_credit_monthly_payment'),
4092                    Configure::read('payment_lite_credit_paid'),
4093                    Configure::read('payment_lite_plan_downgrade'),
4094                    Configure::read('payment_lite_plan_upgrade'),
4095                    Configure::read('payment_credit_change'),
4096                    Configure::read('payment_credit_chocotto_monthly_payment'),
4097                    Configure::read('payment_credit_chocotto_retry'),
4098                    Configure::read('payment_credit_chocotto_force_charge')
4099                ))
4100            ) {
4101                // get current payment_id
4102                $paymentID = $this->Payment->id;
4103
4104                // create new payment receivable
4105                if ($formType != Configure::read('payment_credit_receivable') && $receivablePayment) {
4106                    // set payment id
4107                    $data["payment_id"] = $paymentID;
4108
4109                    $paymentData = array(
4110                        'user_id' => $userId,
4111                        'amount' => $receivablePayment,
4112                        'status' => 1,
4113                        'type_id' => 1,
4114                        'reference_id' => $referenceId,
4115                        'card_company' => $card_company,
4116                        'param1' => json_encode($data),
4117                        'form_type' => Configure::read('payment_credit_receivable'),
4118                        'ordd' => $data["ordd"],
4119                        'currency_code' => Configure::read('currency_jpy'), // set currency id to jpy
4120                        'transaction_code' => $paymentHash,
4121                        'price_id' => $priceId,
4122                        'payment_id' => $paymentPlanId,
4123                        'payment_type' => $paymentType,
4124                        'discounted_amount' => 0
4125                    );
4126
4127                    // create new payment
4128                    $this->Payment->clear();
4129                    $this->Payment->create();
4130                    $this->Payment->set($paymentData);
4131                    if (!$this->Payment->save()) {
4132                        $this->log(__METHOD__ . ' Failed to save payment data' . json_encode($paymentData), $logFileName);
4133                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data', $paymentData);
4134                        return ;
4135                    }
4136
4137                    //update/add user`s settlement amount
4138                    $this->User->updateUserPayments($paymentData);
4139                    // set payment_id
4140                    $paymentID = $this->Payment->id;
4141
4142                }
4143
4144                // set payment receivable statuses to 2 - received
4145                $this->PaymentReceivable->updateReceivableReservationPayment(
4146                    $userData['User']['id'], 
4147                    array(
4148                        'status' => 2,
4149                        'payment_id' => $paymentID,
4150                        'payment_collection_date' => date("Y-m-d H:i:s"),
4151                        'card_company' => $card_company,
4152                        'payment_plan_id' => $paymentPlanId,
4153                        'membership_type_index' => $membershipStatusIndex
4154                    ),
4155                    array(
4156                        'PaymentReceivable.user_id' => $userData['User']['id'],
4157                        'PaymentReceivable.status' => 0,
4158                        'PaymentReceivable.payment_element_type' => 1,
4159                        'PaymentReceivable.created <=' => $cronDateRun
4160                    )
4161                );
4162
4163                // debug log
4164                $this->log("[ZEUSPAY_RECEIVABLE] kickback was recieved -> " . json_encode($data), $logFileName);
4165
4166                // create new payment for appreciation receivable
4167                if ($formType != Configure::read('payment_credit_appreciation_receivable') && $appreciationReceivable > 0) {
4168                    // set payment id
4169                    $data["payment_id"] = $paymentID;
4170                    //reset payment data
4171                    $paymentData = array();
4172
4173                    //set payment data
4174                    $paymentData = array(
4175                        'user_id' => $userId,
4176                        'amount' => $appreciationReceivable,
4177                        'status' => 1,
4178                        'type_id' => 1,
4179                        'reference_id' => $referenceId,
4180                        'card_company' => $card_company,
4181                        'param1' => json_encode($data),
4182                        'form_type' => Configure::read('appreciation_data.payment_form_type'),
4183                        'ordd' => $data["ordd"],
4184                        'currency_code' => Configure::read('currency_jpy'), // set currency id to jpy
4185                        'transaction_code' => $paymentHash,
4186                        'price_id' => $priceId,
4187                        'payment_id' => $paymentPlanId,
4188                        'payment_type' => $paymentType,
4189                        'discounted_amount' => 0
4190                    );
4191
4192                    // create new payment
4193                    $this->Payment->clear();
4194                    $this->Payment->create();
4195                    $this->Payment->set($paymentData);
4196                    if (!$this->Payment->save()) {
4197                        $this->log(__METHOD__ . ' Failed to save appreciationReceivable payment data' . json_encode($paymentData), $logFileName);
4198                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save appreciationReceivable payment data', $paymentData);
4199                        return ;
4200                    }
4201                    //update/add user`s settlement amount
4202                    $this->User->updateUserPayments($paymentData);
4203                    // set payment_id
4204                    $paymentID = $this->Payment->id;
4205
4206                }
4207
4208                // set payment receivable for appreciation statuses to 2 - received
4209                $this->PaymentReceivable->updateReceivableReservationPayment(
4210                    $userData['User']['id'], 
4211                    array(
4212                        'status' => 2,
4213                        'payment_id' => $paymentID,
4214                        'payment_collection_date' => date("Y-m-d H:i:s"),
4215                        'card_company' => $card_company,
4216                        'payment_plan_id' => $paymentPlanId,
4217                        'membership_type_index' => $membershipStatusIndex
4218                    ),
4219                    array(
4220                        'PaymentReceivable.user_id' => $userData['User']['id'],
4221                        'PaymentReceivable.status' => 0,
4222                        'PaymentReceivable.payment_element_type' => Configure::read('appreciation_data.payment_element_type'),
4223                        'PaymentReceivable.created <=' => $cronDateRun
4224                    )
4225                );
4226
4227                // debug log
4228                $this->log("[ZEUSPAY_APPRECIATION_RECEIVABLE] kickback was recieved -> " . json_encode($data), $logFileName);
4229
4230                // create new payment for live lesson receivable
4231                if ($formType != Configure::read('payment_live_lesson_receivable') && $liveLessonReceivable) {
4232                    // set payment id
4233                    $data["payment_id"] = $paymentID;
4234
4235                    $paymentData = array(
4236                        'user_id' => $userId,
4237                        'amount' => $liveLessonReceivable,
4238                        'status' => 1,
4239                        'type_id' => 1,
4240                        'reference_id' => $referenceId,
4241                        'card_company' => $card_company,
4242                        'param1' => json_encode($data),
4243                        'form_type' => Configure::read('payment_live_lesson_receivable'),
4244                        'ordd' => $data["ordd"],
4245                        'currency_code' => Configure::read('currency_jpy'), // set currency id to jpy
4246                        'transaction_code' => $paymentHash,
4247                        'price_id' => $priceId,
4248                        'payment_id' => $paymentPlanId,
4249                        'payment_type' => $paymentType,
4250                        'discounted_amount' => 0
4251                    );
4252
4253                    // create new payment
4254                    $this->Payment->clear();
4255                    $this->Payment->create();
4256                    $this->Payment->set($paymentData);
4257                    if (!$this->Payment->save()) {
4258                        $this->log(__METHOD__ . ' Failed to save payment data' . json_encode($paymentData), $logFileName);
4259                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data', $paymentData);
4260                        return ;
4261                    }
4262                    //update/add user`s settlement amount
4263                    $this->User->updateUserPayments($paymentData);
4264                    // set payment_id
4265                    $paymentID = $this->Payment->id;
4266                }
4267
4268                // set payment receivable for live lesson statuses to 2 - received
4269                $this->PaymentReceivable->updateReceivableReservationPayment(
4270                    $userData['User']['id'], 
4271                    array(
4272                        'status' => 2,
4273                        'payment_id' => $paymentID,
4274                        'payment_collection_date' => date("Y-m-d H:i:s"),
4275                        'card_company' => $card_company,
4276                        'payment_plan_id' => $paymentPlanId,
4277                        'membership_type_index' => $membershipStatusIndex
4278                    ),
4279                    array(
4280                        'PaymentReceivable.user_id' => $userData['User']['id'],
4281                        'PaymentReceivable.status' => 0,
4282                        'PaymentReceivable.payment_element_type' => Configure::read('payment_element_type.live'),
4283                        'PaymentReceivable.created <=' => $cronDateRun
4284                    )
4285                );
4286                
4287                // debug log
4288                $this->log("[ZEUSPAY_LIVE_RECEIVABLE] kickback was recieved -> " . json_encode($data), $logFileName);                
4289
4290            }
4291
4292            // NC-7029: CHECK REFERRAL USER
4293            if (
4294                in_array($formType, array(
4295                    Configure::read('payment_credit_monthly_payment'),
4296                    Configure::read('payment_credit_force_charge'),
4297                    Configure::read('payment_credit_retry'),
4298                    Configure::read('payment_credit_authentication'),
4299                    Configure::read('payment_credit_family_monthly_payment'),
4300                    Configure::read('payment_lite_credit_monthly_payment'),
4301                    Configure::read('payment_lite_credit_paid')
4302                ))
4303            ) {
4304                $ruData = array(
4305                    'referee_id' => $userData['User']['id'],
4306                    'payment_plan_id' => $newYear95percentOffCampaign ? Configure::read('payment_plans.free_trial') : $paymentPlanId,
4307                    'currency_code' => $userData['User']['currency_code'],
4308                    'logFileName' => $logFileName,
4309                    'form_type' => $newYear95percentOffCampaign ? Configure::read('payment_credit_authentication') : $formType
4310                );
4311
4312                $couponReferredData = $this->UsersReferral->checkReferredUser($ruData);
4313                if (isset($couponReferredData['error']) && $couponReferredData['error']) {
4314                    $this->log(__METHOD__ . ' Failed to update users referral event flg.' . json_encode($ruData), $logFileName);
4315                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update users referral event flg.', $ruData);
4316                    return ;
4317                }
4318
4319                $couponMailId = Configure::read('site_in_mail.coupon_mail_template_id');
4320
4321                // send coupon mail to referee
4322                if (isset($couponReferredData['sendMailToReferee']) && $couponReferredData['sendMailToReferee']) {
4323                    $refereeData = array(
4324                        'id' => $userData['User']['id'],
4325                        'email' => $userData['User']['email'],
4326                        'native_language2' => $userData['User']['native_language2'],
4327                        'hash' => $userData['User']['hash'],
4328                        'refereeName' => $userData['User']['nickname'],
4329                        'referrerName' => $couponReferredData['referrerName'],
4330                        'couponAmount' => $couponReferredData['refereeSaveAmount'],
4331                        'couponUpdatedTotal' => $couponReferredData['refereeUpdatedTotal']
4332                    );
4333
4334                    // send mail to referee
4335                    myMailer::sendTemplateMail($couponMailId, $userData['User']['email'], $refereeData, array(), 'User');
4336                }
4337
4338                // send coupon mail to referer
4339                if (isset($couponReferredData['sendMailToReferer']) && $couponReferredData['sendMailToReferer']) {
4340                    $referrerData = array(
4341                        'id' => $couponReferredData['referrerId'],
4342                        'email' => $couponReferredData['referrerEmail'],
4343                        'native_language2' => $couponReferredData['nativeLanguage2'],
4344                        'hash' => $couponReferredData['referrerHash'],
4345                        'refereeName' => $userData['User']['nickname'],
4346                        'referrerName' => $couponReferredData['referrerName'],
4347                        'couponAmount' => $couponReferredData['refererSaveAmount'],
4348                        'couponUpdatedTotal' => $couponReferredData['refererUpdatedTotal']
4349                    );
4350
4351                    // send mail to referrer
4352                    myMailer::sendTemplateMail($couponMailId, $couponReferredData['referrerEmail'], $referrerData, array(), 'User');
4353                }
4354
4355                
4356                if ( //Amazon gift campaign
4357                    in_array($formType, array(
4358                        Configure::read('payment_credit_force_charge'),
4359                        Configure::read('payment_credit_authentication')
4360                    ))
4361                ) {
4362                    ClassRegistry::init('CampaignSettingTable')->amazonGift(array('user_id' => $userData['User']['id'], 'type' => 1));
4363                }
4364            }
4365            
4366            // NJ-47740
4367            $getCouponDiscounDetail = PaymentTable::getCouponDiscountRequestDetail($ptPaymentParams, 'native');
4368            $nativeOptionDiscount = !empty($getCouponDiscounDetail['discounted_amount']) ? $getCouponDiscounDetail['discounted_amount'] : 0;
4369            $nativeCouponRequestId = !empty($getCouponDiscounDetail['coupon_request_id']) ? $getCouponDiscounDetail['coupon_request_id'] : null;
4370            // if has native speaker payment
4371            if (
4372                isset($ptPaymentParams['nativeOptionPayment']) && ($ptPaymentParams['nativeOptionPayment'] > 0 || $nativeOptionDiscount > 0)
4373                && in_array($ptPaymentParams['formType'], array(Configure::read('payment_credit_monthly_payment'), Configure::read('payment_credit_family_monthly_payment')))
4374            ) {
4375                $nspFormType = Configure::read('payment_native_option_monthly_payment');
4376                if (isset($ptPaymentParams['nativeOptionJoin']) && $ptPaymentParams['nativeOptionJoin']) {
4377                    $nspFormType = Configure::read('payment_native_option_join');
4378                }
4379                
4380                // check if family plan
4381                if ($familyId) {
4382                    // change reference id to parent id
4383                    $referenceId = isset($data['sendid']) ? $data['sendid'] : 0;
4384                } else {
4385                    $referenceId = $userId;
4386                }
4387
4388                $paymentData = array(
4389                    'user_id' => $userId,
4390                    'amount' => $ptPaymentParams['nativeOptionPayment'],
4391                    'status' => 1,
4392                    'type_id' => 1,
4393                    'reference_id' => $referenceId,
4394                    'payment_transaction_password' => $ptPassword,
4395                    'card_company' => $card_company,
4396                    'param1' => json_encode($data),
4397                    'form_type' => $nspFormType,
4398                    'ordd' => $data["ordd"],
4399                    'currency_code' => Configure::read('currency_jpy'),
4400                    'transaction_code' => $paymentHash,
4401                    'price_id' => $priceId,
4402                    'payment_id' => $paymentPlanId,
4403                    'payment_type' => Configure::read('payment_types.native_option'),
4404                );
4405                
4406                // NJ-47740
4407                $paymentData['discounted_amount'] = $nativeOptionDiscount;
4408                $paymentData['coupon_request_id'] = $nativeCouponRequestId;
4409
4410                // create new payment
4411                $this->Payment->clear();
4412                $this->Payment->create();
4413                $this->Payment->set($paymentData);
4414                if (!$this->Payment->save()) {
4415                    $this->log(__METHOD__ . ' Failed to save payment data' . json_encode($paymentData), $logFileName);
4416                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data', $paymentData);
4417                    return ;
4418                }
4419                
4420                //update/add user`s settlement amount
4421                $this->User->updateUserPayments($paymentData);
4422                
4423                // NJ-47740
4424                if (!empty($paymentData['coupon_request_id']) && $paymentData['discounted_amount'] > 0) {
4425                    // confirm coupon use request for native discount
4426                    $requestCouponConfirmData = array(
4427                        'grpId' => $paymentData['coupon_request_id'],
4428                        'paymentId' => $this->Payment->id
4429                    );
4430                    $result_confirm = $this->UsersCouponV1->performCouponConfirm($requestCouponConfirmData);
4431                    
4432                    if (!$result_confirm) {
4433                        $this->log(__METHOD__ . ' Failed to confirm native coupon use request. ' . json_encode($requestCouponConfirmData) . ' -- ' . json_encode($data), $logFileName);
4434                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to confirm native coupon use request', $data, $requestCouponConfirmData);
4435                        return ;
4436                    }
4437                }
4438                // NJ-47740 end
4439                
4440                // update payment details
4441                $updatePaymentDetailParams = array(
4442                    'currencyCode' => $paymentData['currency_code'],
4443                    'formType' => $paymentData['form_type'],
4444                    'paymentType' => $paymentData['payment_type'],
4445                    'amount' => $paymentData['amount'],
4446                    'discounted_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0,
4447                    'familyId' => $familyId,
4448                    'cronDateRun' => $cronDateRun,
4449                    'priceId' => $paymentData['price_id'],
4450                    'paymentPlanId' => $paymentData['payment_id'],
4451                    'user_id' => $paymentData['user_id'],
4452                    'coupon_use_request_id' => isset($paymentData['coupon_request_id']) ? $paymentData['coupon_request_id'] : null,
4453                    'coupon_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0
4454                );
4455                
4456                $updatePaymentDetail = array(
4457                    'id' => $ptId,
4458                    'fields' => array(
4459                        'payment_details' => $updatePaymentDetailParams
4460                    )
4461                );
4462
4463                if (!$this->PaymentTransaction->updateWPPaymentTransaction($updatePaymentDetail)) {
4464                    $this->log(__METHOD__ . ' Failed to update payment details. ' . json_encode($updatePaymentDetail), $logFileName);
4465                }
4466            }
4467
4468            // if has callan option payment
4469            // NJ-47740
4470            $getCouponDiscounDetail = PaymentTable::getCouponDiscountRequestDetail($ptPaymentParams, 'callan');
4471            $callanOptionDiscount = !empty($getCouponDiscounDetail['discounted_amount']) ? $getCouponDiscounDetail['discounted_amount'] : 0;
4472            $callanCouponRequestId = !empty($getCouponDiscounDetail['coupon_request_id']) ? $getCouponDiscounDetail['coupon_request_id'] : null;
4473            if (
4474                isset($ptPaymentParams['callanOptionPayment']) && ($ptPaymentParams['callanOptionPayment'] > 0 || $callanOptionDiscount > 0)
4475                && in_array($ptPaymentParams['formType'], array(Configure::read('payment_credit_monthly_payment'), Configure::read('payment_credit_family_monthly_payment')))
4476            ) {
4477                $nspFormType = Configure::read('payment_callan_option_monthly_payment');
4478                if (isset($ptPaymentParams['callanOptionJoin']) && $ptPaymentParams['callanOptionJoin']) {
4479                    $nspFormType = Configure::read('payment_callan_option_join');
4480                }
4481                
4482                // check if family plan
4483                if ($familyId) {
4484                    // change reference id to parent id
4485                    $referenceId = isset($data['sendid']) ? $data['sendid'] : 0;
4486                } else {
4487                    $referenceId = $userId;
4488                }
4489
4490                $paymentData = array(
4491                    'user_id' => $userId,
4492                    'amount' => $ptPaymentParams['callanOptionPayment'],
4493                    'status' => 1,
4494                    'type_id' => 1,
4495                    'reference_id' => $referenceId,
4496                    'payment_transaction_password' => $ptPassword,
4497                    'card_company' => $card_company,
4498                    'param1' => json_encode($data),
4499                    'form_type' => $nspFormType,
4500                    'ordd' => $data["ordd"],
4501                    'currency_code' => Configure::read('currency_jpy'),
4502                    'transaction_code' => $paymentHash,
4503                    'price_id' => $priceId,
4504                    'payment_id' => $paymentPlanId,
4505                    'payment_type' => Configure::read('payment_types.callan_option'),
4506                );
4507                
4508                // NJ-47740
4509                $paymentData['discounted_amount'] = $callanOptionDiscount;
4510                $paymentData['coupon_request_id'] = $callanCouponRequestId;
4511
4512                // create new payment
4513                $this->Payment->clear();
4514                $this->Payment->create();
4515                $this->Payment->set($paymentData);
4516                if (!$this->Payment->save()) {
4517                    $this->log(__METHOD__ . ' Failed to save payment data' . json_encode($paymentData), $logFileName);
4518                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data', $paymentData);
4519                    return ;
4520                }
4521                
4522                //update/add user`s settlement amount
4523                $this->User->updateUserPayments($paymentData);
4524
4525                // NJ-47740
4526                if (!empty($paymentData['coupon_request_id']) && $paymentData['discounted_amount'] > 0) {
4527                    // confirm coupon use request for callan discount
4528                    $requestCouponConfirmData = array(
4529                        'grpId' => $paymentData['coupon_request_id'],
4530                        'paymentId' => $this->Payment->id
4531                    );
4532                    $result_confirm = $this->UsersCouponV1->performCouponConfirm($requestCouponConfirmData);
4533
4534                    if (!$result_confirm) {
4535                        $this->log(__METHOD__ . ' Failed to confirm callan coupon use request. ' . json_encode($requestCouponConfirmData) . ' -- ' . json_encode($data), $logFileName);
4536                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to confirm callan coupon use request', $data, $requestCouponConfirmData);
4537                        return;
4538                    }
4539                }
4540                // NJ-47740 end
4541                
4542                // update payment details
4543                $updatePaymentDetailParams = array(
4544                    'currencyCode' => $paymentData['currency_code'],
4545                    'formType' => $paymentData['form_type'],
4546                    'paymentType' => $paymentData['payment_type'],
4547                    'amount' => $paymentData['amount'],
4548                    'discounted_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0,
4549                    'familyId' => $familyId,
4550                    'cronDateRun' => $cronDateRun,
4551                    'priceId' => $paymentData['price_id'],
4552                    'paymentPlanId' => $paymentData['payment_id'],
4553                    'user_id' => $paymentData['user_id'],
4554                    'coupon_use_request_id' => isset($paymentData['coupon_request_id']) ? $paymentData['coupon_request_id'] : null,
4555                    'coupon_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0
4556                );
4557                
4558                $updatePaymentDetail = array(
4559                    'id' => $ptId,
4560                    'fields' => array(
4561                        'payment_details' => $updatePaymentDetailParams
4562                    )
4563                );
4564
4565                if (!$this->PaymentTransaction->updateWPPaymentTransaction($updatePaymentDetail)) {
4566                    $this->log(__METHOD__ . ' Failed to update payment details. ' . json_encode($updatePaymentDetail), $logFileName);
4567                }
4568            }
4569            
4570            // activate the user native option (new, resume, and monthly payment)
4571            if (isset($ptPaymentParams['nativeOptionPayment']) && ($ptPaymentParams['nativeOptionPayment'] > 0 || $nativeOptionDiscount > 0)) { 
4572
4573                $this->log(__METHOD__ . ' NJ-2388 debug Payment Transaction Data: ' . json_encode($ptData), 'native_option_debug');
4574
4575                // - option process data
4576                $optionProcessData = array(
4577                    'user_id' => $userId,
4578                    'type' => 'on',
4579                    'option_type' => Configure::read('native_speaker.options.all_you_can_eat')
4580                );
4581
4582                $this->User->userNativeOptionProcess($optionProcessData);
4583
4584                //NJ-2814 add logs
4585                if (isset($ptPaymentParams['nativeOptionJoin']) && $ptPaymentParams['nativeOptionJoin']) {
4586                    $nativeStatus = 1; // subscribed
4587                    $statusBefore = '';
4588                } else {
4589                    $nativeStatus = 2; // Monthly Continue
4590                    $statusBefore = 1;
4591                }
4592
4593                $optionAfterName = 'Native Unlimited Option';
4594
4595                $optionLogParams = array(
4596                    'user_id' => $userId,
4597                    'platform' => $ptPaymentParams['platform'],
4598                    'status' => $nativeStatus,
4599                    'controller_name' => $this->request->params['controller'],
4600                    'action_name' => $this->request->params['action'],
4601                    'user_type' => 0, // user
4602                    'option_before' => $statusBefore,
4603                    'option_after' => 1,
4604                    'option_before_name' => '',
4605                    'option_after_name' => $optionAfterName,
4606                    'option_type' => 1,
4607                    'payment_plan_id' => $paymentPlanId
4608                );
4609
4610                ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
4611
4612                // - save registration status step
4613                $stepKey = Configure::read('registration_steps.user_info_entry');
4614                $this->saveStep($userId, $stepKey);
4615            }
4616
4617            // activate the user native option (new, resume, and monthly payment)
4618            if (isset($ptPaymentParams['callanOptionPayment']) && ($ptPaymentParams['callanOptionPayment'] > 0 || $callanOptionDiscount > 0)) { 
4619
4620                $this->log(__METHOD__ . ' NJ-2388 debug Payment Transaction Data: ' . json_encode($ptData), 'native_option_debug');
4621
4622                // - option process data
4623                $optionProcessData = array(
4624                    'user_id' => $userId,
4625                    'type' => 'on',
4626                    'option_type' => Configure::read('callan_unlimited.options.callan_unlimited_option')
4627                );
4628
4629                $this->User->userNativeOptionProcess($optionProcessData);
4630
4631                //NJ-2814 add logs
4632                if (isset($ptPaymentParams['callanOptionJoin']) && $ptPaymentParams['callanOptionJoin']) {
4633                    $nativeStatus = 1; // subscribed
4634                    $statusBefore = '';
4635                } else {
4636                    $nativeStatus = 2; // Monthly Continue
4637                    $statusBefore = 1;
4638                }
4639                $optionAfterName = 'Callan Unlimited Option';
4640                $optionLogParams = array(
4641                    'user_id' => $userId,
4642                    'platform' => $ptPaymentParams['platform'],
4643                    'status' => $nativeStatus,
4644                    'controller_name' => $this->request->params['controller'],
4645                    'action_name' => $this->request->params['action'],
4646                    'user_type' => 0, // user
4647                    'option_before' => $statusBefore,
4648                    'option_after' => 1,
4649                    'option_before_name' => '',
4650                    'option_after_name' => $optionAfterName,
4651                    'option_type' => 2,
4652                    'payment_plan_id' => $paymentPlanId
4653                );
4654
4655                ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
4656            }
4657
4658            // if parent user update children's card company
4659            if ($formType == Configure::read('payment_credit_change')) {
4660                $childList = $this->User->getChildId($userId);
4661
4662                // check if user is parent
4663                if (!empty($childList)) {
4664                    foreach ($childList as $childId) {
4665                        $this->User->clear();
4666                        $updateCCArr = array('card_company' => $card_company);
4667
4668                        //Update also child card exp date same with parent
4669                        if (isset($ptPaymentParams['cardExpirationDate'])) {
4670                            $updateCCArr['card_expiration_date'] = $ptPaymentParams['cardExpirationDate'];
4671                        }
4672
4673                        if (!$this->User->read(array_keys($updateCCArr), $childId)) {
4674                            $this->log(__METHOD__ . ' child id does not exist. ' . json_encode($updateCCArr) . ' parent id --> ' . json_encode($userId), $logFileName);
4675                            $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'child id does not exist.', $updateCCArr);
4676                            return ;
4677                        }
4678
4679                        $this->User->set($updateCCArr);
4680                        if (!$this->User->save()) {
4681                            $this->log(__METHOD__ . ' failed to update child card company. ' . json_encode($updateCCArr) . ' parent id --> ' . json_encode($userId), $logFileName);
4682                            $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'failed to update child card company.', $updateCCArr);
4683                            return ;
4684                        }
4685                    }
4686                }
4687            }
4688
4689            // if light plan
4690            if ($formType == Configure::read('payment_lite_plan_upgrade') && $_allowChangePlan) {
4691                // check if user subscribed to zero student discount option
4692                $discountOptionData = $this->UserDiscountOptionsTerm->getTerm([
4693                    'user_id' =>  $userId,
4694                    'discount_option_id' => Configure::read('discount_option.zero_student.plan_id'),
4695                    'status' => 1
4696                ]);
4697
4698                // stop discount option
4699                if ($discountOptionData) {
4700                    // count successful discount
4701                    $discountCount = $this->DiscountOptionsSettlementHistory->countSuccessfulDiscount($discountOptionData['discount_option_term_id']);
4702                    
4703                    // open tunnel
4704                    myTools::initializeApiTunnel(['DiscountOptionController']);
4705
4706                    // initialize controller
4707                    $doc = new DiscountOptionController();
4708
4709                    $doshStatus = $discountCount ?
4710                        Configure::read('discount_option.dosh_status.midterm_cancellation') :
4711                        Configure::read('discount_option.dosh_status.maturity_cancellation');
4712
4713                    $szsdoParams = [
4714                        'discountOptionId' => $discountOptionData['discount_option_id'],
4715                        'discountOptionPriceId' => $discountOptionData['discount_option_price_id'],
4716                        'termId' => $discountOptionData['discount_option_term_id'],
4717                        'cancellationFee' => 0,
4718                        'cancellationType' => Configure::read('discount_option.dosh_type.plan_change'),
4719                        'userData' => $userData['User'],
4720                        'fromController' => $this->request->params['controller'],
4721                        'fromAction' => $this->request->params['action'],
4722                        'doshStatus' => $doshStatus
4723                    ];
4724
4725                    // set data
4726                    $doc->params = $szsdoParams;
4727
4728                    // stop
4729                    $stopDiscountOption = json_decode($doc->stopDiscountOption(), true);
4730
4731                    if (isset($stopDiscountOption['error']) && $stopDiscountOption['error']) {
4732                        $this->log(__METHOD__ . 'failed to stop zero student discount option: '.json_encode($szsdoParams), 'family_plan');
4733                        $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'failed to stop zero student discount option.', $szsdoParams);
4734                        return ;
4735                    }
4736                }
4737            }
4738
4739            // if study abroad | ryugaku payment
4740            if ($formType == Configure::read('payment_study_abroad')) {
4741                $estimationID = $ptPaymentParams['estimationReuqestID'];
4742                $getEstimationData = $this->RyugakuAdminEstimateRequest->find('first', array(
4743                    'fields' => array(
4744                        'RyugakuAdminEstimateRequest.*',
4745                    ),
4746                    'conditions' => array(
4747                        'RyugakuAdminEstimateRequest.user_id' => $userId,
4748                        'RyugakuAdminEstimateRequest.id' => $estimationID
4749                    ),
4750                    'recursive' => -1
4751                ));
4752
4753                if ($getEstimationData['RyugakuAdminEstimateRequest']) {
4754                    $pricingFeeTypes = Configure::read('admin_request_pricing_fee_types');
4755                    $ordd = $data["ordd"];
4756                    $cm_code = '';
4757                    $response_text = json_encode($data);
4758            
4759                    // save payment data
4760                    $rygakuPaymentData = array();
4761
4762                    // NJ-57361: get estimate request pricings
4763                    $adminEstimateRequestPricings = $this->RyugakuAdminEstimateRequestPricing->getAllRequestPricings($getEstimationData['RyugakuAdminEstimateRequest']['id'], false);
4764                    
4765                    foreach ($adminEstimateRequestPricings as $pricing) {
4766                        $pricing = $pricing['RyugakuAdminEstimateRequestPricing'];
4767                        
4768                        // - set value for amount
4769                        $amount = 0;
4770                        if ($pricing['type'] == $pricingFeeTypes['normal']) {
4771                            $amount = $pricing['fee'];
4772                        } else if ($pricing['type'] == $pricingFeeTypes['special']) {
4773                            $amount = $pricing['special_fee'];
4774                        }
4775
4776                        if ($pricing['taxable_flg']) {
4777                            $amount = $amount * Configure::read('tax.increase');
4778                        }
4779
4780                        if ($amount > 0) {
4781                            $rygakuPaymentData[] = [
4782                                'user_id' => $userId,
4783                                'estimation_request_id' => $estimationID,
4784                                'estimation_request_pricing_id' => $pricing['id'],
4785                                'user_payment_id' => $paymentSaveID,
4786                                'fee_type' => 0,
4787                                'currency_code' => Configure::read('default.user_currency'),
4788                                'amount' => $amount,
4789                                'ordd' => $ordd,
4790                                'cm_code' => $cm_code,
4791                                'response_text' => $response_text,
4792                                'payment_method' => 1 // phase 1
4793                            ];
4794                        }
4795                    }
4796
4797                    // save many to RyugakuSchoolPayment
4798                    $this->RyugakuSchoolPayment->saveMany($rygakuPaymentData);
4799
4800                    // update payment id
4801                    $this->RyugakuAdminEstimateRequest->updateAll(
4802                        array('RyugakuAdminEstimateRequest.payment_id' => $paymentSaveID),
4803                        array('RyugakuAdminEstimateRequest.id' => $estimationID)
4804                    );
4805                }
4806
4807
4808            }
4809
4810            $ptStatus = 1; // success
4811
4812
4813            // - NJ-31307 : trigger campaign
4814            if(!empty($ptPaymentParams['nativeOptionPayment']) || !empty($ptPaymentParams['callanOptionPayment'])){
4815                ClassRegistry::init('CampaignSettingTable')->callanUnlimitedCampaign(array(
4816                    'user_id' => $userId, 
4817                    'trigger' => 3, 
4818                    'pt_params' => $ptData ?? [],
4819                    'payment_type' => 'Zeuspay'
4820                ));
4821            }
4822
4823            // ~ NJ-65811: Logger
4824            if(
4825                $formType == Configure::read('payment_credit_change')
4826                && !empty($ptPassword)
4827                && (int) $monthlyPayment > 0
4828            ){
4829                $creditChangeCacheKey = "credit_change_{$userId}_{$ptPassword}";
4830                $creditChangeCache = $this->memcache->get($creditChangeCacheKey);
4831
4832                if(!$creditChangeCache){
4833                    $this->memcache->set(array(
4834                        'key' => $creditChangeCacheKey,
4835                        'value' => 1,
4836                        'expire' => 3600 // 1 hour
4837                    ));
4838                } else {
4839                    $mySlack = new mySlack();
4840                    $mySlack->channel = myTools::checkChannel("#nc-settlement", "#nc-settlement-dev");
4841                    $mySlack->username = "ZEUS CREDIT CHANGE REPORT";
4842                    $mySlack->text = "```";
4843                    $mySlack->text .= "DUPLICATE RECORD\n\n";
4844                    $mySlack->text .= "PAYMENT TRANSACTION PASSWORD:\n";
4845                    $mySlack->text .= $ptPassword . "\n\n";
4846                    $mySlack->text .= "METHOD\n";
4847                    $mySlack->text .=  __METHOD__ . "\n\n";
4848                    $mySlack->text .= "USER ID:\n";
4849                    $mySlack->text .= $userId . "\n\n";
4850                    $mySlack->text .= "KICKBACK URL:\n";
4851                    $mySlack->text .= $_SERVER['REQUEST_URI'] . "\n\n";
4852                    $mySlack->text .= "EC2 INSTANCE ID:\n";
4853                    $mySlack->text .= exec('ec2-metadata -i') . "\n\n";
4854                    $mySlack->text .= "DATA:\n";
4855                    $mySlack->text .= json_encode($data) . "\n";
4856                    $mySlack->text .= "```";
4857
4858                    try {
4859                        $mySlack->postMessage();
4860                        $this->log(__METHOD__ . ' ZEUS CREDIT CHANGE REPORT : DUPLICATE RECORD ->' . json_encode(["pt_password" => $ptPassword, "data" => $data]) , 'error');
4861                    } catch (Exception $e) {
4862                        CakeLog::write('debug', 'Error sending message: ' . $e->getMessage());    
4863                    }
4864                }
4865                
4866            }
4867
4868
4869        } else {
4870            $changePlanChargeFlg = $ptPaymentParams['changePlanChargeFlg'] ?? false;
4871            # possible fail transactions
4872            $inViableFailTransactions = array(
4873                Configure::read('payment_credit_monthly_payment'),
4874                Configure::read('payment_credit_coin_purchase'),
4875                Configure::read('payment_credit_receivable'),
4876                Configure::read('payment_credit_family_monthly_payment'),
4877                Configure::read('payment_native_option_join'),
4878                Configure::read('payment_native_option_monthly_payment'),
4879                Configure::read('payment_callan_option_join'),
4880                Configure::read('payment_callan_option_monthly_payment'),
4881                Configure::read('payment_lite_credit_monthly_payment'),
4882                Configure::read('payment_credit_chocotto_monthly_payment')
4883            );
4884
4885            # if the form type is a possible fail transaction
4886            if (in_array($formType, $inViableFailTransactions)) {
4887                // return if existing user or new user failed to become family plan paid user
4888                if (
4889                    $formType == Configure::read('payment_credit_family_monthly_payment') && $familyId &&
4890                    isset($ptPaymentParams['new_family_plan']) && $ptPaymentParams['new_family_plan']
4891                ) {
4892                    $this->log(__METHOD__ . 'zeus.error.ng_return_applying_family: '.json_encode($data), 'family_plan');
4893                    $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'failed to update child card company.', $updateCCArr);
4894                    return ;
4895                }
4896
4897                // - save user change membership status
4898                if (Configure::read('payment_credit_monthly_payment') == $formType) {
4899
4900                    $userTable = new UserTable($userData['User']);
4901                    $membershipTypes = UserTable::getEngMembershipTypeData();
4902                    $membershipTypeIndex = $userTable->getMembershipTypeIndex();
4903                    $tipAmount = null;
4904                    $parentId = $userTable->parent_id;
4905                    $is_cron = 0;
4906                    if ($ptPaymentParams['logFileName'] == 'monthly_payment'){
4907                        $is_cron = 1;
4908                    } 
4909
4910                       $currency_after = $userTable->currency_code;
4911                       
4912                       $plan_before = $ptPaymentParams['paymentPlanId'];
4913                    $plan_after = $userTable->payment_plan_id;
4914
4915                    $appreciationFlg = 0;
4916                    $tipAmount = null;
4917                    if (isset($ptPaymentParams['family_data']['applyPlan']['tip_max_amount']) && $ptPaymentParams['family_data']['applyPlan']['tip_max_amount']) {
4918                        $tipAmount = $ptPaymentParams['family_data']['applyPlan']['tip_max_amount'];
4919                    }
4920                    if (isset($ptPaymentParams['family_data']['applyPlan']['allow_appreciation_flg']) && $ptPaymentParams['family_data']['applyPlan']['allow_appreciation_flg'] && $tipAmount) {
4921                        $appreciationFlg = 1;
4922                    }
4923
4924                    $usclData = array(
4925                        'user_id' => $userId,
4926                        'platform' => $userTable->platform ?? '',
4927                        'card_company_before' => $userTable->card_company,
4928                        'status_before' => $membershipTypes[$membershipTypeIndex],
4929                        'status_after' => $membershipTypes[5],
4930                        'controller_name' => $this->request->params['controller'],
4931                        'action_name' => $this->request->params['action'],
4932                        'parent_id' => $parentId,
4933                        'is_cron' => $is_cron,
4934                        'currency_before' => $ptPaymentParams['currencyCode'],
4935                        'currency_after' => $currency_after,
4936                        'payment_plan_id_before' => $plan_before,
4937                        'payment_plan_id_after' => $plan_after,
4938                        'default_appreciation_flg' => $appreciationFlg,
4939                        'default_appreciation_amount' => $tipAmount
4940                    );
4941                    // save user change membership status
4942                    if (!$this->UserStatusChangeLog->saveLog($usclData)) {
4943                        $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'Unable to update status change log', $usclData);
4944                        return;
4945                    }
4946                }
4947
4948                # if form_type is for monthly payment
4949                if (
4950                    (
4951                        Configure::read('payment_credit_monthly_payment') == $formType ||
4952                        Configure::read('payment_credit_family_monthly_payment') == $formType ||
4953                        Configure::read('payment_lite_credit_monthly_payment') == $formType ||
4954                        Configure::read('payment_credit_chocotto_monthly_payment') == $formType
4955                    ) && !$changePlanChargeFlg
4956                ) {
4957                    # set user data
4958                    $this->User->validate = array();
4959                    $userPrevData = $this->User->read(null, $userData['User']['id']);
4960                    if (!$userPrevData) {
4961                        $this->log(__METHOD__ . ' User id does not exist. ' . json_encode($userData), $logFileName);
4962                        $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'User id does not exist', $userData);
4963                        return ;
4964                    }
4965
4966                    //update user memo && native option cancellation time
4967                    $date = date('Y/m/d H:i:s');
4968                    $memoStr = '';
4969                    $memoStr2 = '';
4970                    
4971                    // check if user is subscribed to native option and callan option
4972                    if(isset($userPrevData['User']['native_option']) && $userPrevData['User']['native_option']) { 
4973                        $memoStr = $date." Cancellation of Native Speaker Unlimited option";
4974                    }
4975
4976                    if(isset($userPrevData['User']['callan_option']) && $userPrevData['User']['callan_option']) {
4977                        $memoStr2 = $date." Cancellation of Callan Unlimited option";
4978                    }
4979
4980                    $updatedMemo = $memoStr."\n".$memoStr2."\n".$userPrevData['User']['memo'];
4981                    $userUpdate = array(
4982                        'fail_flg' => '1',
4983                        'counseling_attended_flg' => '1',
4984                        'charge_flg' => '0',
4985                        'allow_appreciation_flg' => '0',
4986                        'show_appreciation_flg' => '0',
4987                        'native_option' => 0,
4988                        'callan_option' => 0,
4989                        'next_charge_date' => NULL,
4990                        'memo' => $updatedMemo
4991                    );
4992
4993                    if (isset($userPrevData['User']['native_option']) && $userPrevData['User']['native_option']) {
4994                        $userUpdate['native_option_cancellation_time'] = $date;
4995                    }
4996
4997                    if (isset($userPrevData['User']['callan_option']) && $userPrevData['User']['callan_option']) {
4998                        $userUpdate['callan_option_cancellation_time'] = $date;
4999                    }
5000
5001                    $this->User->set($userUpdate);
5002                    if (!$this->User->save()) {
5003                        $this->log(__METHOD__ . ' Failed to update user data. ' . json_encode($userUpdate), $logFileName);
5004                        $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed to update user data', $userUpdate);
5005                        return ;
5006                    } else {
5007                        // check if has Native Option
5008                        if (isset($ptPaymentParams['nativeOptionPayment']) && $ptPaymentParams['nativeOptionPayment'] > 0) {
5009                            //NJ-2814 add logs
5010                            if (isset($ptPaymentParams['nativeOptionJoin']) && $ptPaymentParams['nativeOptionJoin']) {
5011                                $nativeStatus = 1; // subscribed
5012                                $statusBefore = $option_before_name = '';
5013                            } else {
5014                                $nativeStatus = 3; // unsubscribed
5015                                $statusBefore = 1;
5016                                $option_before_name = 'Native Unlimited Option';
5017                            }
5018
5019                            $optionLogParams = array(
5020                                'user_id' => $userId,
5021                                'platform' => $ptPaymentParams['platform'],
5022                                'status' => $nativeStatus,
5023                                'controller_name' => $this->request->params['controller'],
5024                                'action_name' => $this->request->params['action'],
5025                                'user_type' => 0, // user
5026                                'option_before' => $statusBefore,
5027                                'option_after' => 1,
5028                                'option_before_name' => $option_before_name,
5029                                'option_after_name' => '',
5030                                'option_type' => 1,
5031                                'payment_plan_id' => $paymentPlanId
5032                            );
5033
5034                            ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
5035                        }
5036
5037                        // check if has Callan Option
5038                        if (isset($ptPaymentParams['callanOptionPayment']) && $ptPaymentParams['callanOptionPayment'] > 0) {
5039                            //NJ-2814 add logs
5040                            if (isset($ptPaymentParams['callanOptionJoin']) && $ptPaymentParams['callanOptionJoin']) {
5041                                $callanStatus = 1; // subscribed
5042                                $statusBefore = $option_before_name = '';
5043                            } else {
5044                                $callanStatus = 3; // unsubscribed
5045                                $statusBefore = 1;
5046                                $option_before_name = 'Callan Unlimited Option';
5047                            }
5048
5049                            $optionLogParams = array(
5050                                'user_id' => $userId,
5051                                'platform' => $ptPaymentParams['platform'],
5052                                'status' => $callanStatus,
5053                                'controller_name' => $this->request->params['controller'],
5054                                'action_name' => $this->request->params['action'],
5055                                'user_type' => 0, // user
5056                                'option_before' => $statusBefore,
5057                                'option_after' => 1,
5058                                'option_before_name' => $option_before_name,
5059                                'option_after_name' => '',
5060                                'option_type' => 2,
5061                                'payment_plan_id' => $paymentPlanId
5062                            );
5063
5064                            ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
5065                        }
5066                    }
5067
5068                    # update user who join in ContinuationCampaign to fail status - 3
5069                    $this->ContinuationCampaign->setFailedUser(array(
5070                        'user_id' => $userData['User']['id']
5071                    ));
5072                    
5073                    // NJ-47740
5074                    // confiscate pending request coupon for native and callan option
5075                    $this->UsersCouponV1->confiscateOptionDiscount(array('userId' => $userId));
5076
5077                    // Get children list
5078                    $childList = $this->User->getChildId($userData['User']['id']);
5079
5080                    // check if user is parent 
5081                    if (!empty($childList)) {
5082                        foreach ($childList as $childId) {
5083                            // get child detail
5084                            $familyMember = $this->User->find('first', array(
5085                                'fields' => array(
5086                                    'User.id',
5087                                    'User.memo',
5088                                    'User.parent_id',
5089                                    'User.native_option',
5090                                    'User.callan_option'
5091                                ),
5092                                'conditions' => array('User.id' => $childId)
5093                            ));
5094                            $familyObj = new UserTable($familyMember['User']);
5095                            $addMemo = 'Family plan[User]: family deactivation parent failed settlement';
5096                            unset($familyObj->parent_id);
5097
5098                            // update children status to free
5099                            if ($this->User->updateStatusToFree($familyObj, $addMemo)) {
5100                                // - deactivate reserved lessons of the children
5101                                $this->LessonSchedule->deactivateDisableReservedLessons($childId, true, false, true, null, false, true);
5102
5103                                // NC-8645: add deactivation lock
5104                                UserTable::saveUserDeactivationLock($childId);
5105
5106                                // NC-5342: add deactivation log
5107                                $this->loadModel('FamilyDeactivationLog');
5108                                $this->FamilyDeactivationLog->addLog($childId);
5109                            }
5110                            
5111                            // NJ-47740
5112                            // confiscate pending request coupon for native and callan option
5113                            $this->UsersCouponV1->confiscateOptionDiscount(array('userId' => $childId));
5114                        }
5115                    }
5116                }
5117
5118                # set error code
5119                $data['error_code'] = Configure::read('zeus.error.ng_return');
5120                if (!$this->_error_log_set($data, $ptPaymentParams)) {
5121                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, '_error_log_set failed', $data);
5122                    return ;
5123                }
5124            } else {
5125            }
5126
5127            if ($nativeOptionPayment > 0 && in_array($formType, array(Configure::read('payment_credit_monthly_payment'), Configure::read('payment_credit_family_monthly_payment')))) {
5128                $data['formType'] = Configure::read('payment_native_option_monthly_payment');
5129                $ptPaymentParams['paymentAmount'] = $nativeOptionPayment;
5130
5131                if (!$this->_error_log_set($data, $ptPaymentParams)) {
5132                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, '_error_log_set failed', $data);
5133                    return ;
5134                }
5135            }
5136
5137            if ($callanOptionPayment > 0 && in_array($formType, array(Configure::read('payment_credit_monthly_payment'), Configure::read('payment_credit_family_monthly_payment')))) {
5138                $data['formType'] = Configure::read('payment_callan_option_monthly_payment');
5139                $ptPaymentParams['paymentAmount'] = $callanOptionPayment;
5140
5141                if (!$this->_error_log_set($data, $ptPaymentParams)) {
5142                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, '_error_log_set failed', $data);
5143                    return ;
5144                }
5145            }
5146
5147            if (isset($ptPaymentParams['annualDiscountOption']) && $formType == Configure::read('payment_halfway_termination_of_annual_discount_option')) {
5148                if (!$this->_error_log_set($data, $ptPaymentParams)) {
5149                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, '_error_log_set failed', $data);
5150                    return ;
5151                }
5152            }
5153
5154            if ($formType != Configure::read('payment_credit_authentication')) {
5155                $ptStatus = 2; // error;
5156            } else {
5157                $ptStatus = 0;
5158            }
5159        }
5160
5161        // update payment transaction
5162        $this->updatePaymentTransaction(array(
5163            'id' => $ptId,
5164            'fields' => array(
5165                'status' => $ptStatus,
5166                'response_text' => array('zp_kickback' => $data)
5167            ),
5168            'logFileName' => $logFileName
5169        ));
5170
5171        // add registration bonus if user registration
5172        if (isset($ptPaymentParams['userRegister']) && $ptPaymentParams['userRegister']) {
5173            
5174            if (
5175                isset($zeroStudentDiscount) && $zeroStudentDiscount &&
5176                $formType != Configure::read('payment_credit_chocotto_free') &&
5177                $formType != Configure::read('payment_credit_chocotto_monthly_payment') &&
5178                $formType != Configure::read('payment_credit_chocotto_retry') &&
5179                $formType != Configure::read('payment_credit_chocotto_force_charge')
5180            ) {
5181                UsersPointHistoryTable::checkDailyBonus($userId, true);
5182            } else {
5183                UsersPointHistoryTable::checkDailyBonus($userId);
5184            }
5185
5186            if (
5187                (isset($ptPaymentParams['campaign95percentOff']) && $ptPaymentParams['campaign95percentOff'])
5188                || (time() >= strtotime(Configure::read('campaign_config.feb_new_registration.period.start')) && time() <= strtotime(Configure::read('campaign_config.feb_new_registration.period.end')))
5189            ) {
5190                $paramsRefBonus = array(
5191                    "type" => 1, // kickback
5192                    "userID" => $userId,
5193                    "userRegister" => true
5194                );
5195                // add referral coin NC-10009
5196                $this->User->addReferralBonus($paramsRefBonus);
5197            }
5198
5199            // - check if lite plan user 
5200            $this->User->clear();
5201            $_currentUser = $this->User->read(array('id','memo','payment_plan_id'), $userId);
5202            $_currentUserMemo = $_currentUser['User']['memo'];
5203
5204            if (in_array($_currentUser['User']['payment_plan_id'], Configure::read('lite_payment_plans'))) {
5205                # update user memo
5206                $_coins = Configure::read('credit.lite_plan_bonus_coin_authentication');
5207                if ($formType == Configure::read('payment_lite_credit_monthly_payment')) {
5208                    $_coins = Configure::read('lite_plan_monthly_coin');
5209                }
5210                $_dateNow = date('Y-m-d H:i:s');
5211                $_updateMemo =  "\n {$_dateNow} Light Plan Bonus: {$_coins}";
5212                $_updateMemo = $_updateMemo . "\n" . $_currentUserMemo;
5213
5214                // - update user memo 
5215                $this->User->clear();
5216                $memUpdateParams = array(
5217                    'id' => $userId,
5218                    'memo' => $_updateMemo
5219                );
5220                $this->User->set($memUpdateParams);
5221                $this->User->save();
5222            }
5223        }
5224
5225
5226        // campaign master trigger 5 
5227        if (strtoupper($data['result']) == 'OK') {
5228            $this->retrial_confiscate_coins([
5229                'formType' => $formType,
5230                'paymentPlanId' => $paymentPlanId,
5231                'userId' => $userId
5232            ]);
5233        }
5234
5235        // - NJ-18780 : lite plan
5236        // Check if the payment result is successful and meets specific conditions for Lite monthly credit payment
5237        if (
5238            strtoupper($data['result']) == 'OK' &&
5239            $formType == Configure::read('payment_lite_credit_monthly_payment') && 
5240            in_array($userData['User']['payment_plan_id'], Configure::read('lite_payment_plans')) && // User must be on a Lite payment plan
5241            (!isset($ptPaymentParams['userRegister']) || !$ptPaymentParams['userRegister']) // Exclude cases where this is a user registration process
5242        ) {
5243            // confisacate and give monthly coin
5244
5245                // - fetch users mc coins
5246                $_monthlyPoints = $this->UsersPoint->getCurrentUserMCPoint($userId); //  mc coins
5247                $_dateNow = date('Y-m-d H:i:s');
5248                $_updateMemo = "";
5249
5250                if ((int) $_monthlyPoints > 0) {
5251                    $_confiscateParams = array(
5252                        'userId' => $userId,
5253                        'point' => $_monthlyPoints,
5254                        'kbn' => 18, // Administrator Change/Minus
5255                        'coinType' => 3
5256                    );
5257
5258                    $conficateLitePoints = $this->UsersPoint->confiscateUserLitePoints($_confiscateParams);
5259
5260                    if ($conficateLitePoints) {
5261                        $_updateMemo = $_updateMemo . "\n {$_dateNow} (Previous Coins (MC)【Confiscated】 : {$_monthlyPoints}. )";
5262                    }
5263                }
5264
5265                $_doneConfiscatePoints = ClassRegistry::init('UsersPointHistory')->confiscateUserLitePointsCoinBox($userId);
5266
5267                // update user memo 
5268                $_currentUser = $this->User->read(array('id','memo','next_charge_date'), $userId);
5269                $_nxtChargeDate = $_currentUser['User']['next_charge_date'];
5270                    
5271                // - set to add monthly coin
5272                $_pointParams = array(
5273                    'userId' => $userId,
5274                    'point' => Configure::read('lite_plan_monthly_coin'),
5275                    'kbn' => Configure::read('lite_plan_bonus_kbn'), // 
5276                    'kbnType' => 1, // add coin
5277                    'coinType' => 3, // mc coin
5278                    'dateExpiration' => $_nxtChargeDate,
5279                    'coinFailMessage' => Configure::read('coin.failed.membership')
5280                );
5281            
5282                // add user's points 
5283                $giveLitePoints = $this->UsersPoint->performPointTransaction($_pointParams);
5284
5285                if ($giveLitePoints) {
5286                    $_coins = Configure::read('lite_plan_monthly_coin');
5287                    $_updateMemo = $_updateMemo . "\n {$_dateNow} | Light Plan Bonus Coins (MC): {$_coins}";
5288                }
5289
5290        
5291                $_currentUserMemo = $_currentUser['User']['memo'];
5292
5293                if (!empty($_updateMemo)) {
5294                    $_updateMemo = $_updateMemo . "\n" . $_currentUserMemo;
5295                    $this->User->clear();
5296                    $this->User->set(array('id' => $userId,'memo' => $_currentUserMemo));
5297                    $this->User->save();
5298                }
5299        }
5300
5301        // send event to adjust
5302        if ($kbResult) {
5303            $adjustParams = array(
5304                'formType' => $formType,
5305                'statusBefore' => isset($ptPaymentParams['statusBefore']) ? $ptPaymentParams['statusBefore'] : null,
5306                'userId' => $userId,
5307                'idfa' => $userData['User']['idfa']
5308            );
5309            UserTable::sendEventToAdjust($adjustParams);
5310        }
5311
5312        //NJ-23626 continuing plan campaign
5313        if ((strtoupper($data['result']) == 'OK' || !empty($ptPaymentParams['coupon_used'])) && in_array($formType, array(Configure::read('payment_credit_retry'), Configure::read('payment_credit_monthly_payment')))){
5314            ClassRegistry::init('CampaignSettingTable')->takingLessonAndContinuePlan(array('user_id' => $userId, 'type' => 3));
5315        }
5316
5317        return ;
5318    } //end zeuspay()
5319
5320    private function saveStep($userId, $stepKey) {
5321        $sp = Configure::read('registration_platforms.sp');
5322        $pc = Configure::read('registration_platforms.pc');
5323        $platformId = $this->RequestHandler->isMobile() ? $sp : $pc;
5324
5325        $saveStepParams = array(
5326            'user_id' => $userId,
5327            'step_key' => $stepKey,
5328            'platform' => $platformId,
5329            'language' => $this->localizeDir
5330        );
5331
5332        ClassRegistry::init('UserRegistrationStatus')->saveStep($saveStepParams);
5333    }
5334    /**
5335     * @api {post} /payment/corporateZeuspay/:sendpoint/:result/:usingCompanyCard/:original_sendid/:sendid/:ordd/:money/:cardbrand/:cardnumber/:payment_id/:error_code/:formType/:user_id corporateZeuspay()
5336     * @apiName corporateZeuspay
5337     * @apiGroup Payment
5338     * @apiDescription This function is used to process corporate payment.
5339     * 
5340     * @apiParam {String} sendpoint payment hash
5341     * @apiParam {String} result result of payment
5342     * @apiParam {String} usingCompanyCard flag if using company card
5343     * @apiParam {String} original_sendid original send id
5344     * @apiParam {String} sendid send id of payment
5345     * @apiParam {String} ordd The order id
5346     * @apiParam {String} money The amount of money
5347     * @apiParam {String} cardbrand The card brand
5348     * @apiParam {String} cardnumber The card number
5349     * @apiParam {String} payment_id The payment id
5350     * @apiParam {String} error_code The error code for payment
5351     * @apiParam {String} formType The form type of payment
5352     * @apiParam {String} user_id The user id
5353     * 
5354     * @apiSuccess {Database} Save saves/update the payment data to database.
5355     * 
5356     * @apiError {PHP} log Logs the error if there is an error in the payment.
5357     * 
5358     * @apiSuccessExample Success Response Corporate admin payment transaction:
5359     * Save/update the payment data to corporate admin payment transaction table.
5360     * @apiSuccessExample Success Response Corporate payment receivable:
5361     * create payment transaction in corporates payment receivable table.
5362     *
5363     * @apiErrorExample Error Response:
5364     * logs the error if there is an error in the payment.
5365     * 
5366     * @apiSampleRequest off
5367     */
5368    public function corporateZeuspay($data) {
5369        $corporateUser = $corporateAdmin = false;
5370        $ptData = array();
5371        $paymentHash = trim($data['sendpoint']); // get payment hash
5372        $kbResultOk = strtoupper($data['result']) == 'OK' ? true : false;
5373        $usingCompanyCard = isset($data['usingCompanyCard']) ? $data['usingCompanyCard'] : false;
5374
5375        if ($usingCompanyCard) {
5376            $this->loadModel('CorporateAdminPaymentTransaction');
5377            $data['original_sendid'] = $data['sendid'];
5378            $data['sendid'] = str_replace('cz', '', $data['sendid']); // remove cz
5379
5380            // get transaction data from corporate admin payment transaction table
5381            if ($ptData =  $this->CorporateAdminPaymentTransaction->getPaymentTransaction(array('payment_hash' => $paymentHash))) {
5382                // return if status value is not 0
5383                if ($ptData['status'] != 0) {
5384                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $data['sendid'], 'Corporate admin payment transaction does not exist or status value is not equals to 0', $data);
5385                    return ;
5386                }
5387                $corporateAdmin = true;
5388            }
5389        }
5390
5391        // if empty $ptData
5392        if (empty($ptData)) {
5393            // get transaction data from payment transaction table
5394            $ptData = $this->PaymentTransaction->getWPPaymentTransaction($paymentHash);
5395
5396            // do nothing if payment transaction (payment hash and status = 0) does not exist.
5397            if (!$ptData) {
5398                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $data['sendid'], 'Payment transaction does not exist or status value is not equals to 0', $data);
5399                return ;
5400            }
5401            $corporateUser = true;
5402        }
5403
5404        if ($corporateAdmin) {
5405            $this->loadModel('CorporateAdminPayment');
5406
5407            $ptpp = json_decode($ptData['payment_params'], true); // decode corporate admin payment transaction payment_params to array
5408            $formType = isset($ptpp['formType']) ? $ptpp['formType'] : null;
5409            $cardExpirationDate = isset($ptpp['cardExpirationDate']) ? $ptpp['cardExpirationDate'] : null;
5410            $ordd = isset($data['ordd']) ? $data['ordd'] : null;
5411            $corporateId = $data['sendid'];
5412
5413            $monthlyPaymentExist = $this->CorporateAdminPayment->find('count', array(
5414                'conditions' => array(
5415                    'corporate_id' => $corporateId,
5416                    'ordd' => $ordd,
5417                    'form_type' => $formType
5418                )
5419            ));
5420
5421            // return if payment already exist
5422            if ($monthlyPaymentExist) {
5423                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $corporateId, 'Corporate admin payment data already exist.', $data);
5424                return ;
5425            }
5426
5427            $ptStatus = 1; // default status value
5428            $insertData = array(
5429                'corporate_id' => $corporateId,
5430                'form_type' => $formType,
5431                'ordd' => $ordd,
5432                'amount' => $data['money'],
5433                'param1' => json_encode($data)
5434            );
5435
5436            if ($kbResultOk) {
5437                if ($formType == Configure::read('payment_credit_authentication')) {
5438                    $updateData = array(
5439                        'card_brand' => $data['cardbrand'],
5440                        'card_number' => $data['cardnumber'],
5441                        'card_expiration_date' => $cardExpirationDate
5442                    );
5443
5444                    // update corporate admin card brand and card number
5445                    if (!$this->Corporate->updateData($updateData, $corporateId)) {
5446                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $corporateId, 'Failed to update corporate admin card brand and card number.', $data);
5447                        return ;
5448                    }
5449                }
5450            } else {
5451                $ptStatus = 2;
5452                $insertData['param2'] = 'error:' . $data['error_code'];
5453            }
5454
5455            // insert corporate admin payment
5456            if (!$this->CorporateAdminPayment->saveData($insertData)) {
5457                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $corporateId, 'Failed to save corporate admin payment data.', $data);
5458                return ;
5459            }
5460
5461            // update corporate admin payment transaction
5462            $responseText = array();
5463            $updateData = array('status' => $ptStatus, 'response_text' => '');
5464            $this->CorporateAdminPaymentTransaction->clear();
5465            $read = $this->CorporateAdminPaymentTransaction->read(array_keys($updateData), $ptData['id']);
5466            $rtArr = !empty($read['CorporateAdminPaymentTransaction']['response_text']) ? json_decode($read['CorporateAdminPaymentTransaction']['response_text'], true) : array();
5467
5468            array_push($responseText, $rtArr, $data);
5469            $updateData['response_text'] = json_encode($responseText);
5470            $this->CorporateAdminPaymentTransaction->set($updateData);
5471            if (!$this->CorporateAdminPaymentTransaction->save()) {
5472                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $corporateId, 'Failed to update corporate payment transaction.', $data);
5473                return;
5474            }
5475
5476            return;
5477        } elseif ($corporateUser) {
5478            $ptpp = json_decode($ptData['payment_params'], true); // decode payment transaction payment_params to array
5479            $formType = isset($ptpp['formType']) ? $ptpp['formType'] : null;
5480            $logFileName = isset($ptpp['logFileName']) && !empty($ptpp['logFileName']) ? $ptpp['logFileName'] : 'debug';
5481            $paymentPlanId = isset($ptpp['paymentPlanId']) ? $ptpp['paymentPlanId'] : null;
5482            $priceId = isset($ptpp['priceId']) ? $ptpp['priceId'] : null;
5483            $cronDateRun = isset($ptpp['cronDateRun']) ? $ptpp['cronDateRun'] : date('Y-m-d H:i:s');
5484            // Override if form type is corporate credit card registration
5485
5486            if (
5487                (
5488                    $formType == Configure::read('corporate_credit_card_registration') ||
5489                    $formType == Configure::read('payment_credit_change')
5490                ) 
5491                &&
5492                isset($ptData['created'])
5493            ) {
5494                $cronDateRun = $ptData['created'];
5495            }
5496
5497            $cardExpirationDate = isset($ptpp['cardExpirationDate']) ? $ptpp['cardExpirationDate'] : null;
5498            $amount = isset($data['money']) ? $data['money'] : 0;
5499            $receivablePayment = $appreciationReceivable = $liveLessonReceivable = 0;
5500            $discounted_amount = isset($ptpp['discounted_amount']) ? $ptpp['discounted_amount'] : 0;
5501            $currencyCode = isset($ptpp['currencyCode']) ? $ptpp['currencyCode'] : Configure::read('currency_jpy');
5502
5503            if (!isset($ptpp['corporateSettlementType']) && $formType != Configure::read('payment_credit_change')) {
5504                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $ptData['user_id'], 'Parameter corporate settlement type is missing.', $data);
5505                return ;
5506            }
5507
5508            $settlementType = $ptpp['corporateSettlementType'];
5509            $settlementTypes = Configure::read('corporate_settlement_types');
5510            $userId = $ptData['user_id'];
5511            $cardCompany = Configure::read('card_company.zeus');
5512
5513            // get user data
5514            $userData = $this->User->find('first', array(
5515                'fields' => array(
5516                    'User.*',
5517                    'Corporate.*'
5518                ),
5519                'joins' => array(
5520                    array(
5521                        'table' => 'corporates',
5522                        'alias' => 'Corporate',
5523                        'type' => 'LEFT',
5524                        'conditions' => 'Corporate.id = User.corporate_id'
5525                    )
5526                ),
5527                'conditions' =>array('User.id' => $userId),
5528                'recursive' => -1
5529            ));
5530
5531            $corporateData = $userData['Corporate'];
5532            $membershipStatusIndex = UserTable::getStudentMembershipStatus($userId);
5533            $userData = $userData['User'];
5534            $corpType = $paymentPlanId ? myTools::getCoporateTypeUsingPaymentPlanId($paymentPlanId) : myTools::getCoporateTypeUsingPaymentPlanId($userData['payment_plan_id']);
5535            $corporateId = isset($ptpp['corporateId']) ? $ptpp['corporateId'] : $userData['corporate_id'];
5536
5537            // - add corp type base on user's selected plan
5538            if ($paymentPlanId) {
5539                $userData['corporate_type'] = $paymentPlanId ? myTools::getCoporateTypeUsingPaymentPlanId($paymentPlanId) : myTools::getCoporateTypeUsingPaymentPlanId($userData['payment_plan_id']);
5540                $corpType = $paymentPlanId ? myTools::getCoporateTypeUsingPaymentPlanId($paymentPlanId) : myTools::getCoporateTypeUsingPaymentPlanId($userData['payment_plan_id']);
5541            }
5542
5543            $corpTypeStandard = Configure::read('corporate_type.standard');
5544            $corpTypePremium = Configure::read('corporate_type.premium');
5545            $corpTypeLight = Configure::read('corporate_type.light');
5546
5547            // - NJ-23781 update users_detail.individual_card_fail_flg
5548            $updateIndividualCardFlgParams = [
5549                'user_data' => $userData,
5550                'form_type' => $formType,
5551                'individual_card_fail_flg' => 1, // 0: success, 1: fail
5552            ];
5553
5554            // NC-8194: check null payment_plan_id and price_id
5555            if (!$paymentPlanId || !$priceId) {
5556                if ($userData['payment_plan_id'] && $userData['price_id']) {
5557                    $paymentPlanId = $userData['payment_plan_id'];
5558                    $priceId = $userData['price_id'];
5559                } else {
5560                    $defPlan = $this->PaymentPlanPrice->getDefaultPlan($userData);
5561                    $paymentPlanId = $defPlan['paymentPlanId'];
5562                    $priceId = $defPlan['priceId'];
5563                }
5564            }
5565
5566            // if standard or premium individual plan user and
5567            if (in_array($corpType, array($corpTypePremium, $corpTypeStandard, $corpTypeLight))) {
5568                if (
5569                    in_array($formType, array(
5570                        Configure::read('payment_credit_receivable'),
5571                        Configure::read('payment_individual_corporate_standard'),
5572                        Configure::read('payment_individual_corporate_premium'),
5573                        Configure::read('payment_prepaid_corporate_light_member'),
5574                        Configure::read('payment_credit_change'),
5575                        Configure::read('corporate_credit_card_registration')
5576                    ))
5577                ) {
5578                    // get receivable reservation payment
5579                    $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun);
5580
5581                    if ($receivablePayment && $receivablePayment <= $amount) {
5582                        $ptpp['paymentAmount'] = $amount -= $receivablePayment;
5583                    }
5584
5585                    // get appreciation receivable payments
5586                    $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('appreciation_data.payment_element_type'));
5587
5588                    if ($appreciationReceivable && $appreciationReceivable <= $amount) {
5589                        $ptpp['paymentAmount'] = $amount -= $appreciationReceivable;
5590                    }
5591
5592                    // get live receivable payments
5593                    $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.live'));
5594
5595                    if ($liveLessonReceivable && $liveLessonReceivable <= $amount) {
5596                        $ptpp['paymentAmount'] = $amount -= $liveLessonReceivable;
5597                    }
5598                }
5599            }
5600
5601            $nativeOptionPayment = 0;
5602            $callanOptionPayment = 0;
5603
5604            // if has native speaker payments
5605            // deduct
5606            if (isset($ptpp['nativeOptionPayment']) && $ptpp['nativeOptionPayment'] > 0 && $formType != Configure::read('payment_native_option_join')) {
5607                $nativeOptionPayment = $ptpp['nativeOptionPayment']; // - native option payment
5608                $ptpp['paymentAmount'] = $amount -= $nativeOptionPayment;
5609            }
5610
5611            // if has callan option payment
5612            if (isset($ptpp['callanOptionPayment']) && $ptpp['callanOptionPayment'] > 0 && $formType != Configure::read('payment_callan_option_join')) {
5613                $callanOptionPayment = $ptpp['callanOptionPayment']; // - callan option payment
5614                $ptpp['paymentAmount'] = $amount -= $callanOptionPayment;
5615            }
5616
5617            // set transaction
5618
5619            if ($kbResultOk) {
5620                $ptPassword = isset($ptData['password']) ? $ptData['password'] : null;
5621                $paymentType = isset($ptpp['paymentType']) ? $ptpp['paymentType'] : null;
5622                $basicFee = isset($ptpp['basicFee']) ? $ptpp['basicFee'] : 0;
5623                $lessonFee = isset($ptpp['lessonFee']) ? $ptpp['lessonFee'] : 0;
5624                $ordd = isset($data['ordd']) ? $data['ordd'] : null;
5625
5626                $formTypeIndiLight = Configure::read('payment_prepaid_corporate_light_member');
5627                $formTypeIndiLightLesson = Configure::read('payment_prepaid_corporate_light_member_lesson');
5628                $formTypeComCardLightlLesson = Configure::read('payment_company_credit_corporate_light_lesson');
5629
5630                // corporate payment receivable types
5631                $cprTypes = array(
5632                    $corpTypeStandard => $this->CorporatesPaymentReceivable->typeCorporateStandard,
5633                    $corpTypePremium => $this->CorporatesPaymentReceivable->typeCorporatePremium,
5634                    $corpTypeLight => $this->CorporatesPaymentReceivable->typeCorporateLight
5635                );
5636
5637                /** -- >> START << insert or update corporate payment receivable -- **/
5638
5639                if ($formType != $formTypeIndiLight) {
5640                    // user registration or re-enroll
5641                    if (
5642                        in_array($settlementType, array($settlementTypes['card_registration'], $settlementTypes['force_charge_payment'])) &&
5643                        isset($ptpp['addCorporateReceivable'])
5644                    ) {
5645                        $addCPRData = $ptpp['addCorporateReceivable'];
5646                        $chargeFlg = $corporateData['payment_method'] == 1 ? 1 : 0;
5647                        // insert
5648                        if (isset($addCPRData['amount']) && isset($addCPRData['discount'])) {
5649                            $insertData = array(
5650                                'corporate_id' => $corporateId,
5651                                'user_id' => $userId,
5652                                'type' => isset($cprTypes[$corpType]) ? $cprTypes[$corpType] : 0,
5653                                'status' => 1, // paid
5654                                'quantity' => 1,
5655                                'amount' => $addCPRData['amount'],
5656                                'discount' => $addCPRData['discount'],
5657                                'next_settlement' => date('Y-m-d 00:00:00'),
5658                                'payment_collection_date' => date('Y-m-d H:i:s'),
5659                                'charge_flg' => $chargeFlg
5660                            );
5661
5662                            // create corporate payment receivable
5663                            $createSuccess = $this->CorporatesPaymentReceivable->addReceivablePayment($insertData);
5664
5665                            // rollback and return if failed to create payment receivable
5666                            if (!$createSuccess) {
5667                                $this->log(__METHOD__ . ' Failed to create payment receivable. --> ' . json_encode($insertData) . ' -- ' . json_encode($data), $logFileName);
5668                                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to create payment receivable.', $data);
5669                                return ;
5670                            }
5671                        }
5672
5673                        // insert lesson fee
5674                        if (isset($addCPRData['lessonFeeAmount']) && isset($addCPRData['lessonFeeQty'])) {
5675                            $insertData = array(
5676                                'corporate_id' => $corporateId,
5677                                'user_id' => $userId,
5678                                'type' => $this->CorporatesPaymentReceivable->typeCorporateLightLessonFee,
5679                                'status' => 1, // paid
5680                                'quantity' => $addCPRData['lessonFeeQty'],
5681                                'amount' => $addCPRData['lessonFeeAmount'],
5682                                'discount' => 0,
5683                                'next_settlement' => date('Y-m-d 00:00:00')
5684                            );
5685
5686                            // create corporate payment receivable for lesson fee
5687                            $createSuccess = $this->CorporatesPaymentReceivable->addReceivablePayment($insertData);
5688
5689                            // rollback and return if failed to create payment receivable for lesson fee
5690                            if (!$createSuccess) {
5691                                $this->log(__METHOD__ . ' Failed to create payment receivable for lesson fee. --> ' . json_encode($insertData) . ' -- ' . json_encode($data), $logFileName);
5692                                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to create payment receivable for lesson fee.', $data);
5693                                return ;
5694                            }
5695                        }
5696                    }
5697
5698                    // user withdrawn or monthly payment or monthly payment retry - lesson fee payment
5699                    if ($settlementType == $settlementTypes['lesson_fee_payment']) {
5700                        // insert
5701                        if (isset($ptpp['addCorporateReceivable'])) {
5702                            $addCPRData = $ptpp['addCorporateReceivable'];
5703
5704                            if (isset($addCPRData['lessonFeeAmount']) && isset($addCPRData['lessonFeeQty'])) {
5705                                $insertData = array(
5706                                    'corporate_id' => $corporateId,
5707                                    'user_id' => $userId,
5708                                    'type' => $this->CorporatesPaymentReceivable->typeCorporateLightLessonFee,
5709                                    'status' => 1, // paid
5710                                    'quantity' => $addCPRData['lessonFeeQty'],
5711                                    'amount' => $addCPRData['lessonFeeAmount'],
5712                                    'discount' => 0,
5713                                    'next_settlement' => date('Y-m-d 00:00:00')
5714                                );
5715
5716                                // create corporate payment receivable for lesson fee
5717                                $createSuccess = $this->CorporatesPaymentReceivable->addReceivablePayment($insertData);
5718
5719                                // rollback and return if failed to create payment receivable for lesson fee
5720                                if (!$createSuccess) {
5721                                    $this->log(__METHOD__ . ' Failed to create payment receivable for lesson fee. --> ' . json_encode($insertData) . ' -- ' . json_encode($data), $logFileName);
5722                                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to create payment receivable for lesson fee.', $data);
5723                                    return ;
5724                                }
5725                            }
5726                        }
5727
5728                        // update
5729                        if (isset($ptpp['updateCorporateReceivable'])) {
5730                            $cprParams = array(
5731                                'userId' => $userId,
5732                                'corporateId' => $userData['corporate_id'],
5733                                'type' => $this->CorporatesPaymentReceivable->typeCorporateLightLessonFee
5734                            );
5735
5736                            // update lesson fee status to paid
5737                            $updateSuccess = $this->CorporatesPaymentReceivable->updateReceivablePaymentToPaid($cprParams);
5738
5739                            // rollback and return if failed to update lesson fee status to paid
5740                            if (!$updateSuccess) {
5741                                $this->log(__METHOD__ . ' Failed to update payment lesson fee status to paid. --> ' . json_encode($data), $logFileName);
5742                                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update lesson fee status to paid.', $data);
5743                                return ;
5744                            }
5745                        }
5746                    }
5747
5748                    // monthly payment or monthly payment retry or payment retry or force charge payment
5749                    if (
5750                        (in_array(
5751                            $settlementType,
5752                            array(
5753                                $settlementTypes['monthly_payment'],
5754                                $settlementTypes['monthly_payment_retry'],
5755                                $settlementTypes['retry_payment'],
5756                                $settlementTypes['force_charge_payment']
5757                            )
5758                        ) || $formType == Configure::read('payment_credit_change')) && isset($ptpp['updateCorporateReceivable'])
5759                    ) {
5760                        $cprParams = array(
5761                            'userId' => $userId,
5762                            'corporateId' => $userData['corporate_id']
5763                        );
5764
5765                        // update payment receivable(s) status to paid (including lesson fee)
5766                        $updateSuccess = $this->CorporatesPaymentReceivable->updateReceivablePaymentToPaid($cprParams);
5767
5768                        // rollback and return if failed to update payment receivble(s) status to paid
5769                        if (!$updateSuccess) {
5770                            $this->log(__METHOD__ . ' Failed to update payment receivable(s) status to paid. --> ' . json_encode($data), $logFileName);
5771                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update payment receivable(s) status to paid.', $data);
5772                            return ;
5773                        }
5774                    }
5775
5776                    // corporate admin retry payment
5777                    if ($settlementType == $settlementTypes['retry_payment'] && isset($ptpp['companyCardRetryReceivableId'])) {
5778                        // update staus to paid
5779                        $updateSuccess = $this->CorporatesPaymentReceivable->updateReceivablePaymentToPaid(array('id' => $ptpp['companyCardRetryReceivableId']));
5780
5781                        // rollback and return if failed to update status to paid
5782                        if (!$updateSuccess) {
5783                            $this->log(__METHOD__ . ' Failed to update value to paid. --> ' . json_encode($data), $logFileName);
5784                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update status to paid.', $data);
5785                            return ;
5786                        }
5787
5788                        // udate corporate admin
5789                        if (isset($ptpp['updateCorporateAdminCardInfo'])) {
5790                            $updateData = array(
5791                                'card_brand' => $data['cardbrand'],
5792                                'card_number' => $data['cardnumber'],
5793                            );
5794
5795                            if (isset($cardExpirationDate)) {
5796                                $updateData['card_expiration_date'] = $cardExpirationDate;
5797                            }
5798
5799                            // update corporate admin card brand and card number
5800                            if (!$this->Corporate->updateData($updateData, $corporateId)) {
5801                                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update corporate admin card brand and card number.', $data);
5802                                return ;
5803                            }
5804                        }
5805                    }
5806                // individual light plan
5807                } else {
5808                    if (!in_array($settlementType, array($settlementTypes['card_registration'], $settlementTypes['lesson_fee_payment']))) {
5809                        // update status to paid
5810                        $updateSuccess = $this->CorporatePaymentMemberReceivable->updateReceivableStatus(array('user_id' => $userId));
5811
5812                        // rollback and return if failed to update status to paid
5813                        if (!$updateSuccess['result']) {
5814                            $this->log(__METHOD__ . ' Failed to update status to paid. --> ' . json_encode($data), $logFileName);
5815                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update status to paid.', $data);
5816                            return ;
5817                        }
5818                    }
5819                }
5820                /** -- >> END << insert or update corporate payment receivable -- **/
5821                $receivableFormTypeArr = array( 
5822                    Configure::read('payment_credit_receivable'),
5823                    Configure::read('payment_credit_appreciation_receivable'),
5824                    Configure::read('payment_live_lesson_receivable')
5825                );
5826
5827                $userData = $this->User->find('first', array(
5828                    'conditions' =>array('id' => $userId),
5829                    'recursive' => -1
5830                ));
5831
5832                $userData = $userData['User'];
5833                $currency_before_payment = $userData['currency_code'];
5834                $plan_id_before_payment = $userData['payment_plan_id'];
5835
5836                $paymentData = array(
5837                    'user_id' => $userId,
5838                    'amount' => $amount,
5839                    'status' => 1,
5840                    'reference_id' => $data['sendid'],
5841                    'payment_transaction_password' => $ptPassword,
5842                    'card_company' => $cardCompany,
5843                    'param1' => json_encode($data),
5844                    'form_type' => $formType,
5845                    'ordd' => $ordd,
5846                    'transaction_code' => $paymentHash,
5847                    'currency_id' => Configure::read('default.settlement_currency_id'), // set currency id to jpy
5848                    'currency_code' => $currencyCode,
5849                    'payment_id' => $paymentPlanId,
5850                    'price_id' => $priceId,
5851                    'payment_type' => $paymentType,
5852                    'discounted_amount' => $discounted_amount
5853                );
5854
5855                // - if not receivable payment
5856                if( !in_array( $formType, $receivableFormTypeArr ) ) {
5857                    // add basic fee and/or lesson fee if corporate light
5858                    if ($corpType == $corpTypeLight) {
5859                        if ($userData['corporate_last_charge_date']) {
5860                            $paymentData["lesson_fee_date_started"] = $userData['corporate_last_charge_date'];
5861                        }
5862
5863                        // basic fee
5864                        if ($formType == $formTypeIndiLight || $formType == Configure::read('payment_company_credit_corporate_light')) {
5865                            $paymentData['amount'] = $basicFee;
5866                            $paymentData['basic_fee'] = $basicFee;
5867                            $paymentData['lesson_fee'] = 0;
5868
5869                            // has lesson fee
5870                            if (isset($lessonFee) && $lessonFee > 0) {
5871                                $forLessonFee = $paymentData; // copy
5872                                $forLessonFee['amount'] = $lessonFee;
5873                                $forLessonFee['lesson_fee'] = $lessonFee;
5874                                $forLessonFee['basic_fee'] = 0;
5875
5876                                // change to lesson fee form type
5877                                if ($formType == $formTypeIndiLight) {
5878                                    $forLessonFee['form_type'] = $formTypeIndiLightLesson;
5879                                } else {
5880                                    $forLessonFee['form_type'] = $formTypeComCardLightlLesson;
5881                                }
5882
5883                                // create new payment for lesson fee
5884                                $this->Payment->clear();
5885                                $this->Payment->create();
5886                                $this->Payment->set($forLessonFee);
5887
5888                                // rollback if payment was not saved
5889                                if (!$this->Payment->save()) {
5890                                    $this->log(__METHOD__ . ' Failed to save light plan lesson fee payment. --> ' . json_encode($forLessonFee) . ' -- ' . json_encode($data), $logFileName);
5891                                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save light plan lesson fee payment.', $data);
5892                                    return ;
5893                                }
5894
5895                                //update/add user`s settlement amount
5896                                $this->User->updateUserPayments($paymentData);
5897                            }
5898                        } else {
5899                            if (isset($lessonFee) && $lessonFee > 0) {
5900                                $paymentData['lesson_fee'] = $lessonFee;
5901                            }
5902                        }
5903                    }
5904
5905                    // create new payment
5906                    $this->Payment->clear();
5907                    $this->Payment->create();
5908                    $this->Payment->set($paymentData);
5909
5910                    // rollback if payment was not saved
5911                    if (!$this->Payment->save()) {
5912                        $this->log(__METHOD__ . ' Failed to save payment data. --> ' . json_encode($paymentData) . ' -- ' . json_encode($data), $logFileName);
5913                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data.', $data);
5914                        return ;
5915                    }
5916
5917                    //update/add user`s settlement amount
5918                    $this->User->updateUserPayments($paymentData);
5919                }
5920
5921                // - process after payment logic
5922                if (
5923                    $formType != Configure::read('corporate_credit_card_registration') &&
5924                    $formType != Configure::read('payment_credit_textbook_purchase') &&
5925                    $formType != Configure::read('payment_credit_coin_purchase') &&
5926                    $formType != Configure::read('payment_prepaid_corporate_light_member_lesson') &&
5927                    $formType != Configure::read('payment_company_credit_corporate_light_lesson') &&
5928                    $formType != Configure::read('payment_credit_receivable') &&
5929                    $formType != Configure::read('payment_native_option_join') &&
5930                    $formType != Configure::read('payment_native_option_monthly_payment') &&
5931                    $formType != Configure::read('payment_callan_option_join') &&
5932                    $formType != Configure::read('payment_callan_option_monthly_payment') &&
5933                    $formType != Configure::read('payment_credit_appreciation_receivable') &&
5934                    isset($corporateId) && isset($corpType) &&
5935                    $settlementType != 'lesson_fee_payment'
5936                ) {
5937
5938                    $counselingAttendedFlg = $corpType == $corpTypeLight ? 1 : 0;
5939                    $datetime = date('Y-m-d H:i:s');
5940
5941                    $this->Corporate->openDBReplica();
5942                    $corporateSpeakingMustFlg = $this->Corporate->find('first', array(
5943                            'conditions' => array('Corporate.id' => $corporateId),
5944                            'fields' => 'Corporate.monthly_speaking_business_attended_must_flg'
5945                        )
5946                    );
5947                    $this->Corporate->closeDBReplica();
5948                    $monthlySpeakingBusinessAttendedMustFlg = $corporateSpeakingMustFlg['Corporate']['monthly_speaking_business_attended_must_flg'];
5949
5950
5951                    $saveUserArr = array(
5952                        'status' => 1,
5953                        'modified' => $datetime,
5954                        'fail_flg' => 0,
5955                        'charge_flg' => 1,
5956                        'counseling_attended_flg' => $counselingAttendedFlg,
5957                        'hash16' => $userId,
5958                        'last_charge_date' => $datetime,
5959                        'payment_plan_id' => $paymentPlanId,
5960                        'price_id' => $priceId,
5961                        'double_check_flg' => 0,
5962                        'expired_card_flg' => 0,
5963                        'sms_through_flg' => 1,
5964                        'corporate_type' => $corpType,
5965                        'monthly_speaking_business_attended_must_flg' => $monthlySpeakingBusinessAttendedMustFlg
5966                        // 'native_option' => 0,
5967                        // 'callan_option' => 0,
5968                        // 'unli_native_personal_card_flg' => 0,
5969                        // 'unli_callan_personal_card_flg' => 0
5970                    );
5971
5972                    if (!isset($userData['corporate_id']) || $userData['corporate_id'] != $corporateId) {
5973                        $saveUserArr['corporate_id'] = $corporateId;
5974                    }
5975
5976                    if (
5977                        $usingCompanyCard &&
5978                        !isset($userData['card_brand']) &&
5979                        !isset($userData['card_number'])
5980                    ) {
5981                        $saveUserArr['card_company'] = null;
5982                    } else {
5983                        $saveUserArr['card_company'] = $cardCompany;
5984                    }
5985
5986                    if (!$usingCompanyCard) {
5987                        $saveUserArr['card_number'] = $data['cardnumber'];
5988                        $saveUserArr['card_brand'] = $data['cardbrand'];
5989                    }
5990
5991                    // if form type prepaid coporate light
5992                    if (
5993                        $formType == Configure::read('payment_prepaid_corporate_light_member') ||
5994                        $formType == Configure::read('payment_company_credit_corporate_light')
5995                    ) {
5996                        $saveUserArr['corporate_last_charge_date'] = $datetime;
5997                    }
5998
5999                    // if bonus coin flg is set
6000                    if (isset($ptpp['bonusCoinFlg'])) {
6001                        $saveUserArr['bonus_coin_flg'] = $ptpp['bonusCoinFlg'];
6002                    }
6003
6004                    // if first time payment
6005                    if (isset($userData['first_charge_date']) && $userData['first_charge_date'] == "0000-00-00 00:00:00") {
6006                        $saveUserArr['first_charge_date'] = $datetime;
6007                    }
6008
6009                    // get user zero student discount term
6010                    $discountOptionTermData = $this->UserDiscountOptionsTerm->getTerm([
6011                        'user_id' =>  $userId,
6012                        'discount_option_id' => Configure::read('discount_option.zero_student.plan_id'),
6013                        'status' => 1
6014                    ]);
6015
6016                    // stop zero student discount
6017                    if ($discountOptionTermData) {
6018                        // open tunnel
6019                        myTools::initializeApiTunnel(['DiscountOptionController']);
6020
6021                        // initialize controller
6022                        $doc = new DiscountOptionController(); 
6023
6024                        $zeroStudentDiscountCount = $this->DiscountOptionsSettlementHistory->countSuccessfulDiscount($discountOptionTermData['discount_option_term_id']);
6025                        $doshStatus = $zeroStudentDiscountCount ? Configure::read('discount_option.dosh_status.midterm_cancellation') : Configure::read('discount_option.dosh_status.maturity_cancellation');
6026
6027                        $docParams = [
6028                            'discountOptionId' => $discountOptionTermData['discount_option_id'],
6029                            'discountOptionPriceId' => $discountOptionTermData['discount_option_price_id'],
6030                            'termId' => $discountOptionTermData['discount_option_term_id'],
6031                            'cancellationFee' => 0,
6032                            'cancellationType' => Configure::read('discount_option.dosh_type.plan_change'),
6033                            'userData' => $userData,
6034                            'fromController' => $this->request->params['controller'],
6035                            'fromAction' => $this->request->params['action'],
6036                            'doshStatus' => $doshStatus
6037                        ];
6038
6039                        // set data
6040                        $doc->params = $docParams;
6041
6042                        if (!$doc->stopDiscountOption()) {
6043                            $this->log(__METHOD__ . ' Failed to stop discount option. ' . json_encode($docParams) . ' -- ' . json_encode($data), $logFileName);
6044                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to stop discount option. ', $docParams);
6045                            return ;
6046                        }
6047                    }
6048
6049                    if ($formType != Configure::read('payment_credit_change')) {
6050
6051                        //NJ-38376 : set the corporate light params on next charge date 
6052                        $nxtChargeLightParams = array(
6053                            'user_corporate_type' => $corpType,
6054                            'corporate_id' => $userData['corporate_id']
6055                        );
6056
6057
6058                        // get next charge date
6059                        if ($corpType == $corpTypeLight) {
6060                            $nextChargeDate = $this->User->corpLightNextChargeDate(false,$nxtChargeLightParams);
6061                        } else {
6062                            $nextChargeDate = $this->User->getCorporateNextChargeDate(false,$nxtChargeLightParams);
6063                        }
6064
6065                        $saveUserArr['next_charge_date'] = $nextChargeDate;
6066
6067                        // if corporate premium and card registration or force settlement
6068                        if (
6069                            $corpType == $corpTypePremium &&
6070                            ($logFileName == 'card_charge' || $logFileName == 'card_registration')
6071                        ) {
6072                            $saveUserArr['corporate_campaign_flg'] = 1;
6073                        }
6074                    }
6075
6076                    // NC-7779 : check if user has chivox monthly test taken for the current month, and monthly_speaking_attended_flg ON,
6077                    // turn Off the flag if users has not yet taken the exam for the current month.
6078                    if (
6079                        isset($userData['monthly_speaking_attended_flg']) && isset($userData['monthly_speaking_business_attended_flg'])
6080                        && ($userData['monthly_speaking_attended_flg'] == 1 || $userData['monthly_speaking_business_attended_flg'] == 1)
6081                    ) {
6082                        // check chivox monthly
6083                        $paymentPlanIdsForChivoxMonthly = Configure::read('chivox.monthly.user_payment_plan_cantake_exam');
6084                        if (in_array($paymentPlanId, $paymentPlanIdsForChivoxMonthly)) {
6085
6086                            // load model
6087                            $this->loadModel("UsersChivoxMonthlyTest");
6088                            $userTestMonthFlagParams['user_id'] = $userId;
6089                            $userTestMonthFlag = $this->UsersChivoxMonthlyTest->checkUserCurrentMonthExam($userTestMonthFlagParams);
6090
6091                            $monthly_speaking_attended_flg = Configure::read('chivox.test_data_test_type.daily'); // test_type daily speaking 0
6092                            $monthly_speaking_business_attended_flg = Configure::read('chivox.test_data_test_type.business'); // test_type business 1
6093
6094                            // if user hat not yet taken the exam for current month
6095                            if (!in_array($monthly_speaking_attended_flg, $userTestMonthFlag)) {
6096                                $saveUserArr['monthly_speaking_attended_flg'] = 0;
6097                            }
6098                            if (!in_array($monthly_speaking_business_attended_flg, $userTestMonthFlag)) {
6099                                $saveUserArr['monthly_speaking_business_attended_flg'] = 0;
6100                            }
6101                        }
6102                    }
6103
6104                    $this->User->clear();
6105                    if (!$this->User->read(array_keys($saveUserArr), $userId)) {
6106                        $this->log(__METHOD__ . ' User does not exist. --> ' . json_encode($saveUserArr) . ' -- ' . json_encode($data), $logFileName);
6107                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'User does not exist.', $data);
6108                        return ;
6109                    }
6110
6111                    $this->User->set($saveUserArr);
6112                    $this->User->validate = array();
6113
6114                    // rollback if updating user data failed.
6115                    if (!$saveUser = $this->User->save()) {
6116                        $this->log(__METHOD__ . ' Failed to update user data. --> ' . json_encode($saveUserArr) . ' -- ' . json_encode($data), $logFileName);
6117                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update user data.', $data);
6118                        return ;
6119                    }
6120
6121                    if ($formType != Configure::read('payment_credit_change')) {
6122                        /* --- get remaining points --- */
6123                        // note: only for premium, corporate standardard plan and light plan
6124
6125
6126                        $monthlyPoints = 0;
6127                        if (in_array($paymentPlanId, array(Configure::read('payment_plans.corporate_standard_card_plan'), Configure::read('payment_plans.corporate_premium_individual_plan'), Configure::read('payment_plans.corporate_premium_card_plan')))) {
6128                            $dateDiff = date('t');
6129                            $coins = $dateDiff * 100;
6130                            $coinType = 3; // corporate coins
6131                            $monthlyPoints = $this->UsersPoint->getCorporatePoints($userId, $coinType);
6132                            $memoCoins = 'MC';
6133                        } elseif (in_array($paymentPlanId, array(Configure::read('payment_plans.corporate_light_individual_plan'), Configure::read('payment_plans.corporate_light_card_plan')))) {
6134                            $corporate = $this->Corporate->find('first', array(
6135                                'fields' => array('light_limit'),
6136                                'conditions' => array('id' => $userData['corporate_id']),
6137                                'recursive' => -1
6138                            ));
6139
6140                            $lightLimit = isset($corporate['Corporate']['light_limit']) ?  $corporate['Corporate']['light_limit'] : 1;
6141                            $coins = $lightLimit * $this->Corporate->corpLightMonthlyCoin;
6142                            //if corporate_light_individual_plan grant sc and mc else grant mc
6143                            $coinType = $paymentPlanId == Configure::read('payment_plans.corporate_light_individual_plan') ? 5 : 3; // sc and mc coins
6144                            $monthlyPoints = $this->UsersPoint->getCorporatePoints($userId, $coinType);
6145                            $memoCoins = 'SC and MC';
6146                        }
6147
6148                        /* -- consfiscate points --- */
6149                        // note: only for premium,corporate standardard plan and light plan
6150
6151                        $updateMemo = '';
6152                        if (
6153                            (in_array($paymentPlanId, array(Configure::read('payment_plans.corporate_premium_individual_plan'), Configure::read('payment_plans.corporate_light_individual_plan'))) &&
6154                            $settlementType != $settlementTypes['card_registration']  || in_array($paymentPlanId, array(Configure::read('payment_plans.corporate_standard_card_plan'), Configure::read('payment_plans.corporate_premium_card_plan'), Configure::read('payment_plans.corporate_light_card_plan')))) && $monthlyPoints
6155                        ) {
6156                            $confiscateParams = array(
6157                                'userId' => $userId,
6158                                'point' => $monthlyPoints,
6159                                'kbn' => 18, // Administrator Change/Minus
6160                                'coinType' => $coinType
6161                            );
6162
6163                            // rollback if confiscating points failed
6164                            if (!$confiscateCoinFlg = $this->UsersPoint->confiscateCorporateUserPoints($confiscateParams)) {
6165                                $this->log(__METHOD__ . ' Failed to confiscate points. --> ' . json_encode($confiscateParams) . ' -- ' . json_encode($data), $logFileName);
6166                                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to confiscate points.', $data);
6167                                return ;
6168                            }
6169
6170                            $updateMemo = "\n {$datetime} (Previous Coins ({$memoCoins})【Confiscated】 : {$monthlyPoints}. )";
6171                        }
6172
6173                        /* -- add points and update memo --- */
6174                        // note: only for premium and light plan
6175                        if (in_array($paymentPlanId, array(Configure::read('payment_plans.corporate_premium_individual_plan'), Configure::read('payment_plans.corporate_light_individual_plan'), Configure::read('payment_plans.corporate_premium_card_plan'), Configure::read('payment_plans.corporate_light_card_plan')))) {
6176                            $pointParams = array(
6177                                'userId' => $userId,
6178                                'point' => $coins,
6179                                'kbn' => 19, // Corporate Complimentary (MC)
6180                                'kbnType' => 1, // add coin
6181                                'coinType' => 3, // corporate coin
6182                                'coinFailMessage' => Configure::read('coin.failed.membership')
6183                            );
6184
6185                            // rollback if adding points failed
6186                            if (!$this->UsersPoint->performPointTransaction($pointParams)) {
6187                                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'adding points failed.', $data);
6188                                return ;
6189                            }
6190
6191                            $planName = $paymentPlanId == Configure::read('payment_plans.corporate_light_individual_plan') ? 'Light' : 'Premium';
6192                            $updateMemo = "\n {$datetime} | Corporate {$planName} Plan Monthly Bonus Coins (MC): {$coins} {$updateMemo}";
6193                        // create point data if standard corporate type
6194                        } elseif (
6195                            $paymentPlanId == Configure::read('payment_plans.corporate_standard_individual_plan') && 
6196                            $settlementType == $settlementTypes['card_registration']
6197                        ) {
6198                            if (!$this->UsersPoint->createUsersPoint($userId)) {
6199                                $this->log(__METHOD__ . ' Failed to create users point data. --> ' . json_encode($data), $logFileName);
6200                                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to create users point data.', $data);
6201                                return ;
6202                            }
6203                        }
6204
6205                        if (!empty($updateMemo)) {
6206                            $updateMemo = $updateMemo . "\n" . $userData['memo'];
6207                            $this->User->read(array('memo'), $userId);
6208                            $this->User->set(array('memo' => $updateMemo));
6209                            $this->User->validate = array();
6210
6211                            // rollback if updating memo failed
6212                            if (!$this->User->save()) {
6213                                $this->log(__METHOD__ . ' Failed update user memo. ' . json_encode($updateMemo) . ' -- ' . json_encode($data), $logFileName);
6214                                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed update user memo.', $data);
6215                                return ;
6216                            }
6217                        }
6218                    }
6219
6220                    // set deactivation time
6221                    if (isset($ptpp['corporate_deactivation_time'])) {
6222                        $this->CorporateScheduledDeactivation->clear();
6223                        $this->CorporateScheduledDeactivation->create();
6224
6225                        $cdtParams = array(
6226                            'user_id' => $userId,
6227                            'deactivation_date' => $ptpp['corporate_deactivation_time'],
6228                            'status' => 0
6229                        );
6230                        $this->CorporateScheduledDeactivation->set($cdtParams);
6231
6232                        if (!$this->CorporateScheduledDeactivation->save()) {
6233                            $this->log(__METHOD__ . ' Failed to set deactivation time. --> ' . json_encode($cdtParams) . ' -- ' . json_encode($data), $logFileName);
6234                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to set deactivation time.', $data);
6235                            return ;
6236                        }
6237                    }
6238                } elseif ($formType == Configure::read('payment_credit_coin_purchase')) {
6239                    $coinPurchasePoints = intVal($ptpp['coinPurchasePoints']);
6240                    $coinData = $this->UsersPoint->SET_charge_overseas_menue($coinPurchasePoints, $currencyCode);
6241
6242                    // NC-5007 add to the user's existing coin
6243                    $pcCorZeusPay = array(
6244                        'userId' => $userId,
6245                        'point' => $coinData['num_of_coin'] - $coinData['bonus_coin'],
6246                        'kbn' => 7,
6247                        'kbnType' => 1, // add coin
6248                        'coinType' => 1, // purchase coin
6249                        'coinFailMessage' => Configure::read('coin.failed.buy_coin'),
6250                        'device' => isset($ptpp['device']) ? $ptpp['device'] : null
6251                    );
6252    
6253                    $scCorZeusPay = array(
6254                        'userId' => $userId,
6255                        'point' => $coinData['bonus_coin'],
6256                        'kbn' => 7,
6257                        'kbnType' => 1, // add coin
6258                        'coinType' => 2, // service coin
6259                        'coinFailMessage' => Configure::read('coin.failed.buy_coin'),
6260                        'device' => isset($ptpp['device']) ? $ptpp['device'] : null
6261                    );
6262
6263                    $pointParams = [$pcCorZeusPay, $scCorZeusPay];
6264
6265                    // NC-5007 add to the user's existing coin
6266                    if ( $pointParams ) {
6267                        foreach($pointParams as $key => $val) {
6268                            if (!$this->UsersPoint->performPointTransaction($val)) {
6269                                $this->log(__METHOD__ . ' Failed to add user point. ' . json_encode($val) . ' -- ' . json_encode($data), $logFileName);
6270                                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to add user point', $data, $val);
6271                                return ;
6272                            }
6273                        }
6274                    }
6275
6276                    $cpilData = array(
6277                        'payment_id' => $this->Payment->id,
6278                        'form_type' => $formType,
6279                        'corporate_id' => $corporateId
6280                    );
6281
6282                    // rollback and return if failed to save payment id
6283                    if (!$this->CorporatePaymentIdLog->saveData($cpilData)) {
6284                        $this->log(__METHOD__ . ' Failed to save corporate payment id log data. ' . json_encode($cpilData) . ' -- ' . json_encode($data), $logFileName);
6285                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save corporate payment id log data.', $data);
6286                        return ;
6287                    }
6288                } elseif ($formType == Configure::read('payment_credit_textbook_purchase')) {
6289                    // set textbook sales info
6290                    $textbookSales = $this->TextbookSale->find('first', array(
6291                        'conditions' => array('TextbookSale.sales_code' => $ptPassword),
6292                        'recursive' => -1
6293                    ));
6294
6295                    // if has textbook sales, update payment_id
6296                    if ($textbookSales) {
6297                        $this->TextbookSale->clear();
6298                        if (!$this->TextbookSale->read(null, $textbookSales['TextbookSale']['id'])) {
6299                            $this->log(__METHOD__ . ' Textbook sales id does not exist. --> ' . json_encode($textbookSales), $logFileName);
6300                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Textbook sales id does not exist.', $data);
6301                            return ;
6302                        }
6303
6304                        $this->TextbookSale->set('payment_id', $this->Payment->id);
6305                        $this->TextbookSale->set('payment_status', 1);
6306                        if (!$this->TextbookSale->save()) {
6307                            $this->log(__METHOD__ . ' Failed update textbook sales payment status to 1. --> ' . json_encode($textbookSales), $logFileName);
6308                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed update textbook sales payment status to 1.', $data);
6309                            return ;
6310                        }
6311
6312                        $cpilData = array(
6313                            'payment_id' => $this->Payment->id,
6314                            'form_type' => $formType,
6315                            'corporate_id' => $corporateId
6316                        );
6317
6318                        // rollback and return if failed to save payment id
6319                        if (!$this->CorporatePaymentIdLog->saveData($cpilData)) {
6320                            $this->log(__METHOD__ . ' Failed to save corporate payment id log data. ' . json_encode($cpilData) . ' -- ' . json_encode($data), $logFileName);
6321                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save corporate payment id log data.', $data);
6322                            return ;
6323                        }
6324                    }
6325                } elseif ($formType == Configure::read('corporate_credit_card_registration')) {
6326                    $saveUserArr = array(
6327                        'card_number' => $data['cardnumber'],
6328                        'card_brand' => $data['cardbrand'],
6329                        'card_company' => $cardCompany
6330                    );
6331
6332                    // update user info
6333                    $this->User->clear();
6334                    if (!$this->User->read(array_keys($saveUserArr), $userId)) {
6335                        $this->log(__METHOD__ . ' User does not exist. --> ' . json_encode($saveUserArr) . ' -- ' . json_encode($data), $logFileName);
6336                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'User does not exist.', $data);
6337                        return ;
6338                    }
6339
6340                    $this->User->set($saveUserArr);
6341                    $this->User->validate = array();
6342
6343                    // rollback if updating user data failed.
6344                    if (!$saveUser = $this->User->save()) {
6345                        $this->log(__METHOD__ . ' Failed to update user data. --> ' . json_encode($saveUserArr) . ' -- ' . json_encode($data), $logFileName);
6346                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update user data.', $data);
6347                        return ;
6348                    }
6349                } elseif (in_array($formType, array($formTypeIndiLightLesson, $formTypeComCardLightlLesson)) && $settlementType == $settlementTypes['lesson_fee_payment']) {
6350                    // update corporate last charge date
6351                    $this->User->clear();
6352
6353                    if (!$this->User->read(array('corporate_last_charge_date'), $userId)) {
6354                        $this->log(__METHOD__ . ' User does not exist. --> ' . json_encode($userId) . ' -- ' . json_encode($data), $logFileName);
6355                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, ' User does not exist.', $data);
6356                        return ;
6357                    }
6358
6359                    $this->User->set(array('corporate_last_charge_date' => date('Y-m-d H:i:s')));
6360                    if (!$this->User->save()) {
6361                        $this->log(__METHOD__ . ' Failed to update user corporate_last_charge_date. --> ' . json_encode($userId) . ' -- ' . json_encode($data), $logFileName);
6362                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, ' Failed to update user corporate_last_charge_date.', $data);
6363                        return ;
6364                    }
6365                }
6366
6367                // if card expiration date is not empty
6368                if (
6369                    isset($cardExpirationDate) &&
6370                    !in_array($paymentPlanId, array(Configure::read('payment_plans.corporate_standard_card_plan'), Configure::read('payment_plans.corporate_premium_card_plan')))
6371                ) {
6372                    $this->User->clear();
6373                    $cedData = array('card_expiration_date' => $cardExpirationDate);
6374                    if (!$this->User->read(array_keys($cedData), $userId)) {
6375                        $this->log(__METHOD__ . ' User not found. --> ' . json_encode($userId), $logFileName);
6376                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'User not found.', $data);
6377                        return ;
6378                    }
6379
6380                    $this->User->set($cedData);
6381                    if (!$this->User->save()) {
6382                        $this->log(__METHOD__ . ' Failed to update card expiration date. --> ' . json_encode($cedData) . ' -- ' . json_encode($data), $logFileName);
6383                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to set deactivation time.', $data);
6384                        return ;
6385                    }
6386                }
6387
6388                // [ZEUS] Corporate
6389                if (
6390                    in_array($formType, array(
6391                        Configure::read('payment_credit_receivable'),
6392                        Configure::read('payment_individual_corporate_standard'),
6393                        Configure::read('payment_individual_corporate_premium'),
6394                        Configure::read('payment_prepaid_corporate_light_member'),
6395                        Configure::read('payment_credit_change'),
6396                        Configure::read('corporate_credit_card_registration')
6397                    ))
6398                ) {
6399                    // get current payment_id
6400                    $originalPaymentId = isset($this->Payment->id) ? $this->Payment->id : null;
6401                    
6402                    // create new payment receivable
6403                    if ($receivablePayment) {
6404                        // set payment id
6405                        $data["payment_id"] = $originalPaymentId;
6406                        $paymentData = array(
6407                            'user_id' => $userId,
6408                            'amount' => $receivablePayment,
6409                            'status' => 1,
6410                            'type_id' => 1,
6411                            'reference_id' => $data['sendid'],
6412                            'card_company' => $cardCompany,
6413                            'param1' => json_encode($data),
6414                            'form_type' => Configure::read('payment_credit_receivable'),
6415                            'ordd' => $ordd,
6416                            'currency_code' => $currencyCode,
6417                            'transaction_code' => $paymentHash,
6418                            'price_id' => $priceId,
6419                            'payment_id' => $paymentPlanId,
6420                            'payment_type' => $paymentType,
6421                            'discounted_amount' => $discounted_amount
6422                        );
6423
6424                        // create new payment
6425                        $this->Payment->clear();
6426                        $this->Payment->create();
6427                        $this->Payment->set($paymentData);
6428
6429                        if (!$this->Payment->save()) {
6430                            $this->log(__METHOD__ . ' Failed to save payment data. --> ' . json_encode($paymentData), $logFileName);
6431                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data.', $data);
6432                            return ;
6433                        }
6434
6435                        //update/add user`s settlement amount
6436                        $this->User->updateUserPayments($paymentData);
6437
6438                        // set payment_id
6439                        $paymentID = $this->Payment->id;
6440
6441                        // set payment receivable statuses to 2 - received
6442                        $this->PaymentReceivable->updateReceivableReservationPayment(
6443                            $userId,
6444                            array(
6445                                'status' => 2,
6446                                'payment_id' => $paymentID,
6447                                'payment_collection_date' => date("Y-m-d H:i:s"),
6448                                'card_company' => $cardCompany,
6449                                'payment_plan_id' => $paymentPlanId,
6450                                'membership_type_index' => $membershipStatusIndex
6451                            ),
6452                            array(
6453                                'PaymentReceivable.user_id' => $userId,
6454                                'PaymentReceivable.status' => 0,
6455                                'PaymentReceivable.payment_element_type' => 1,
6456                                'PaymentReceivable.created <=' => $cronDateRun
6457                            )
6458                        );
6459                    }
6460                    
6461                    // [ZEUS] Corporate Appreciation
6462                    if ($appreciationReceivable) {
6463                        $data["payment_id"] = $originalPaymentId;
6464                        $paymentData = array(
6465                            'user_id' => $userId,
6466                            'amount' => $appreciationReceivable,
6467                            'status' => 1,
6468                            'type_id' => 1,
6469                            'reference_id' => $data['sendid'],
6470                            'card_company' => $cardCompany,
6471                            'param1' => json_encode($data),
6472                            'form_type' => Configure::read('appreciation_data.payment_form_type'),
6473                            'ordd' => $ordd,
6474                            'currency_code' => $currencyCode,
6475                            'transaction_code' => $paymentHash,
6476                            'price_id' => $priceId,
6477                            'payment_id' => $paymentPlanId,
6478                            'payment_type' => $paymentType,
6479                            'discounted_amount' => $discounted_amount
6480                        );
6481
6482                        // create new payment
6483                        $this->Payment->clear();
6484                        $this->Payment->create();
6485                        $this->Payment->set($paymentData);
6486
6487                        if (!$this->Payment->save()) {
6488                            $this->log(__METHOD__ . ' Failed to save appreciationReceivable payment data. --> ' . json_encode($paymentData), $logFileName);
6489                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data.', $data);
6490                            return ;
6491                        }
6492
6493                        //update/add user`s settlement amount
6494                        $this->User->updateUserPayments($paymentData);
6495
6496                        // set payment_id
6497                        $paymentID = $this->Payment->id;
6498
6499                        // set payment receivable for appreciation statuses to 2 - received
6500                        $this->PaymentReceivable->updateReceivableReservationPayment(
6501                            $userId,
6502                            array(
6503                                'status' => 2,
6504                                'payment_id' => $paymentID,
6505                                'payment_collection_date' => date("Y-m-d H:i:s"),
6506                                'card_company' => $cardCompany,
6507                                'payment_plan_id' => $paymentPlanId,
6508                                'membership_type_index' => $membershipStatusIndex
6509                            ),
6510                            array(
6511                                'PaymentReceivable.user_id' => $userId,
6512                                'PaymentReceivable.status' => 0,
6513                                'PaymentReceivable.payment_element_type' => Configure::read('appreciation_data.payment_element_type'), // Appreciation
6514                                'PaymentReceivable.created <=' => $cronDateRun
6515                            )
6516                        );
6517                    }
6518
6519                    // debug log
6520                    $this->log("[ZEUSPAY_CORPORATE_APPRECIATION_RECEIVABLE] kickback was recieved -> " . json_encode($data), $logFileName);
6521
6522                    // [ZEUS] Corporate Live
6523                    if ($liveLessonReceivable) {
6524                        $data["payment_id"] = $originalPaymentId;
6525                        $paymentData = array(
6526                            'user_id' => $userId,
6527                            'amount' => $liveLessonReceivable,
6528                            'status' => 1,
6529                            'type_id' => 1,
6530                            'reference_id' => $data['sendid'],
6531                            'card_company' => $cardCompany,
6532                            'param1' => json_encode($data),
6533                            'form_type' => Configure::read('payment_live_lesson_receivable'),
6534                            'ordd' => $ordd,
6535                            'currency_code' => $currencyCode,
6536                            'transaction_code' => $paymentHash,
6537                            'price_id' => $priceId,
6538                            'payment_id' => $paymentPlanId,
6539                            'payment_type' => $paymentType,
6540                            'discounted_amount' => $discounted_amount
6541                        );
6542
6543                        // create new payment
6544                        $this->Payment->clear();
6545                        $this->Payment->create();
6546                        $this->Payment->set($paymentData);
6547
6548                        if (!$this->Payment->save()) {
6549                            $this->log(__METHOD__ . ' Failed to save liveLessonReceivable payment data. --> ' . json_encode($paymentData), $logFileName);
6550                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data.', $data);
6551                            return ;
6552                        }
6553
6554                        //update/add user`s settlement amount
6555                        $this->User->updateUserPayments($paymentData);
6556
6557                        // set payment_id
6558                        $paymentID = $this->Payment->id;
6559
6560                        // set payment receivable for live statuses to 2 - received
6561                        $this->PaymentReceivable->updateReceivableReservationPayment(
6562                            $userId,
6563                            array(
6564                                'status' => 2,
6565                                'payment_id' => $paymentID,
6566                                'payment_collection_date' => date("Y-m-d H:i:s"),
6567                                'card_company' => $cardCompany,
6568                                'payment_plan_id' => $paymentPlanId,
6569                                'membership_type_index' => $membershipStatusIndex
6570                            ),
6571                            array(
6572                                'PaymentReceivable.user_id' => $userId,
6573                                'PaymentReceivable.status' => 0,
6574                                'PaymentReceivable.payment_element_type' => Configure::read('payment_element_type.live'),
6575                                'PaymentReceivable.created <=' => $cronDateRun
6576                            )
6577                        );
6578                    }
6579                    
6580                    // debug log
6581                    $this->log("[ZEUSPAY_CORPORATE_LIVE_RECEIVABLE] kickback was recieved -> " . json_encode($data), $logFileName);
6582
6583                }
6584
6585                // if has native speaker payment
6586                if ($nativeOptionPayment > 0 && $formType != Configure::read('payment_native_option_join')) {
6587                    $paymentData['amount'] = $ptpp['nativeOptionPayment'];
6588                    $paymentData['form_type'] = Configure::read('payment_native_option_monthly_payment');
6589
6590                    // create new payment
6591                    $this->Payment->clear();
6592                    $this->Payment->create();
6593                    $this->Payment->set($paymentData);
6594                    $this->Payment->validate = array();
6595                    $this->Payment->set($paymentData);
6596
6597                    if (!$this->Payment->save()) {
6598                        $this->log(__METHOD__ . ' Failed to save native option payment data. --> ' . json_encode($paymentData) . ' -- ' . json_encode($data), $logFileName);
6599                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save native option payment data.', $data);
6600                        return ;
6601                    }
6602
6603                    //update/add user`s settlement amount
6604                    $this->User->updateUserPayments($paymentData);
6605                }
6606
6607                // if has callan unli option payment
6608                if ($callanOptionPayment > 0 && $formType != Configure::read('payment_callan_option_join')) {
6609                    $paymentData['amount'] = $ptpp['callanOptionPayment'];
6610                    $paymentData['form_type'] = Configure::read('payment_callan_option_monthly_payment');
6611
6612                    // create new payment
6613                    $this->Payment->clear();
6614                    $this->Payment->create();
6615                    $this->Payment->set($paymentData);
6616                    $this->Payment->validate = array();
6617                    $this->Payment->set($paymentData);
6618
6619                    if (!$this->Payment->save()) {
6620                        $this->log(__METHOD__ . ' Failed to save native option payment data. --> ' . json_encode($paymentData) . ' -- ' . json_encode($data), $logFileName);
6621                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save native option payment data.', $data);
6622                        return ;
6623                    }
6624
6625                    //update/add user`s settlement amount
6626                    $this->User->updateUserPayments($paymentData);
6627                }
6628
6629                // activate user native option
6630                if (isset($ptpp['nativeOptionJoin']) && $ptpp['nativeOptionJoin']) {
6631                    $this->User->clear();
6632                    $unliNativePersonalCardFlg = $this->User->field('unli_native_personal_card_flg', array('User.id' => $userId));
6633                    if (isset($unliNativePersonalCardFlg) && $unliNativePersonalCardFlg != 1) { // prevent duplicate running userNativeOptionProcess function
6634                        if (!$this->User->userNativeOptionProcess(array('user_id' => $userId, 'type' => 'on'))) {
6635                            $this->log(__METHOD__ . 'Failed to update native option. --> ' . json_encode($paymentData) . ' -- ' . json_encode($data), $logFileName);
6636                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update native option.', $data);
6637                            return ;
6638                        }
6639                    }
6640
6641                    //NJ-2814 add logs
6642                    if (isset($ptpp['nativeOptionJoin']) && $ptpp['nativeOptionJoin']) {
6643                        $nativeStatus = 1; // subscribed
6644                        $statusBefore = '';
6645                    } else {
6646                        $nativeStatus = 2; // Monthly Continue
6647                        $statusBefore = 1;
6648                    }
6649
6650                    $optionLogParams = array(
6651                        'user_id' => $userId,
6652                        'platform' => $ptpp['platform'],
6653                        'status' => $nativeStatus,
6654                        'controller_name' => $this->request->params['controller'],
6655                        'action_name' => $this->request->params['action'],
6656                        'user_type' => 0, // user
6657                        'option_before' => $statusBefore,
6658                        'option_after' => 1,
6659                        'option_before_name' => '',
6660                        'option_after_name' => 'Native Unlimited Option',
6661                        'payment_plan_id' => $paymentPlanId
6662                    );
6663
6664                    ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
6665
6666                    $charge_flg = 0;                    
6667                    if (isset($ptpp['corporatePersonalCardFlg']) && $ptpp['corporatePersonalCardFlg']) { 
6668                        $charge_flg = $ptpp['corporatePersonalCardFlg'];
6669                    }
6670
6671                    $insertCPRData = array(
6672                        'corporate_id' => $corporateId,
6673                        'user_id' => $userId,
6674                        'type' => $this->CorporatesPaymentReceivable->typeCorporateNativeOptionJoin,
6675                        'status' => 1, // paid
6676                        'charge_flg' => $charge_flg,
6677                        'quantity' => 1,
6678                        'amount' => $ptpp['nativeOptionPayment'],
6679                        'discount' => 0,
6680                        'next_settlement' => date('Y-m-d 00:00:00')
6681                    );
6682
6683                    // create corporate payment receivable
6684                    if (!$this->CorporatesPaymentReceivable->addReceivablePayment($insertCPRData)) {
6685                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to create payment receivable.', $data);
6686                        return ;
6687                    }
6688                }
6689
6690                // -  activate user callan option
6691                if (isset($ptpp['callanOptionJoin']) && $ptpp['callanOptionJoin']) {
6692
6693                    $charge_flg = 0;
6694                    if (isset($ptpp['corporatePersonalCardFlg']) && $ptpp['corporatePersonalCardFlg']) {
6695                        $charge_flg = $ptpp['corporatePersonalCardFlg'];
6696                    }
6697
6698                    // - option process data
6699                    $optionProcessData = array(
6700                            'user_id' => $userId,
6701                            'type' => 'on',
6702                            'option_type' => Configure::read('callan_unlimited.options.callan_unlimited_option'),
6703                            'corp_student_personal_card' => $charge_flg
6704                    );
6705                    if (!$this->User->userNativeOptionProcess($optionProcessData)) {
6706                        $this->log(__METHOD__ . 'Failed to update native option. --> ' . json_encode($paymentData) . ' -- ' . json_encode($data), $logFileName);
6707                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update callan option.', $data);
6708                        return;
6709                    }
6710
6711
6712                    $insertCPRData = array(
6713                            'corporate_id' => $corporateId,
6714                            'user_id' => $userId,
6715                            'type' => $this->CorporatesPaymentReceivable->typeCorporateCallanOptionJoin,
6716                            'status' => 1, // paid
6717                            'charge_flg' => $charge_flg,
6718                            'quantity' => 1,
6719                            'amount' => $ptpp['callanOptionPayment'],
6720                            'discount' => 0,
6721                            'next_settlement' => date('Y-m-d 00:00:00')
6722                    );
6723
6724                    // create corporate payment receivable
6725                    if (!$this->CorporatesPaymentReceivable->addReceivablePayment($insertCPRData)) {
6726                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to create payment receivable.', $data);
6727                        return ;
6728                    }
6729                }
6730
6731                // [ZEUS] Corporate individual allow appreciation
6732                if (
6733                    in_array($formType, array(
6734                        Configure::read('corporate_credit_card_registration'),
6735                        Configure::read('payment_individual_corporate_standard'),
6736                        Configure::read('payment_individual_corporate_premium'),
6737                        Configure::read('payment_prepaid_corporate_light_member')
6738                    ))
6739                ) {
6740                    // NJ-1562 - appreciation on
6741                    if( $paymentPlanId && in_array( $paymentPlanId, Configure::read('appreciation.payment_plan_id') ) ) {
6742                        $saveUserArr['allow_appreciation_flg'] = 1; // on NJ-7548 corporate individual allow appreciation
6743
6744                        //check if not on family plan
6745                        if (
6746                            !in_array($paymentPlanId, Configure::read('appreciation.can_coin_purchase_check')) 
6747                        ) {
6748                            //NJ-7548 fetch the user birthday and age 
6749                            $userAge = UserTable::getStudentAge($userData['birthday']);
6750                            $userAge = $userAge ? (int) $userAge : null;
6751                            $showAppreciationFlg = 0;
6752
6753                            //change the show appreciation flg if no birthday set or 18 and above            
6754                            if (!$userAge || $userAge >= 18) {
6755                                $showAppreciationFlg = 1;
6756                            }
6757
6758                            //set to save show appreciation flg 
6759                            $saveUserArr['show_appreciation_flg'] = $showAppreciationFlg;
6760                        }
6761
6762                        // update user info
6763                        $this->User->clear();
6764                        if (!$this->User->read(array_keys($saveUserArr), $userId)) {
6765                            $this->log(__METHOD__ . ' User does not exist. --> ' . json_encode($saveUserArr) . ' -- ' . json_encode($data), $logFileName);
6766                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'User does not exist.', $data);
6767                            return ;
6768                        }
6769
6770                        $this->User->set($saveUserArr);
6771                        $this->User->validate = array();
6772
6773                        // rollback if updating user data failed.
6774                        if (!$saveUser = $this->User->save()) {
6775                            $this->log(__METHOD__ . ' Failed to update user data. --> ' . json_encode($saveUserArr) . ' -- ' . json_encode($data), $logFileName);
6776                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update user data.', $data);
6777                            return ;
6778                        }
6779                    }
6780                }
6781
6782                // update corporate activation management data
6783                // add corporate activation management log
6784                if (isset($ptpp['camData']) ) {
6785                    $camData = $ptpp['camData'];
6786                    $camUpdateData = [];
6787
6788                    // if start/resume plan
6789                    if (isset($camData['startCorporatePlan']) && $camData['startCorporatePlan']) {
6790                        $camUpdateData['reserve_plan_status'] = 2; // started
6791                    }
6792
6793                    // if start/resume native option plan
6794                    if (
6795                        (isset($ptpp['nativeOptionPayment']) && $ptpp['nativeOptionPayment'] > 0) ||
6796                        isset($ptpp['callanOptionPayment']) && $ptpp['callanOptionPayment'] > 0
6797                    ) {
6798                        $camUpdateData = ['native_option_plan_status' => 2]; // started
6799                    }
6800
6801                    if (isset($camData['camId'])) {
6802                        $camUpdateData += [
6803                            'reserve_plan_id' => $corpType,
6804                            'reserve_plan_start_date' => date("Y-m-d H:i:s"),
6805                            'reserve_plan_status' => 2,
6806                            'temporary_next_charge_date' => $nextChargeDate
6807                        ];
6808
6809                        if (!$camRes = $this->CorporateActivationManagement->updateCAMData($camUpdateData, $camData['camId'])) {
6810                            $this->log(__METHOD__ . ' Failed to update corporate activation management data. --> ' . json_encode($camUpdateData) . ' -- ' . json_encode($data), $logFileName);
6811                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update corporate activation management data.', $data);
6812                            return ;
6813                        }
6814                    } else {
6815                        $camlInsertData = [
6816                            'user_id' => $userId,
6817                            'corporate_id' => $corporateId,
6818                            'reserve_plan_id' => $corpType,
6819                            'reserve_plan_start_date' => date("Y-m-d H:i:s"),
6820                            'reserve_plan_status' => 2,
6821                            'temporary_next_charge_date' => $nextChargeDate,
6822                            'temporary_pw_flg' => 0,
6823                            'new_user_flg' => 0
6824                        ];
6825
6826                        $camInsertData = [
6827                            'user_id' => $userId,
6828                            'corporate_id' => $corporateId,
6829                            'reserve_plan_id' => $corpType,
6830                            'reserve_plan_start_date' => date("Y-m-d H:i:s"),
6831                            'reserve_plan_status' => 2,
6832                            'temporary_next_charge_date' => $nextChargeDate,
6833                            'temporary_pw_flg' => 0,
6834                            'new_user_flg' => 0
6835                        ];
6836    
6837                        if (!$camRes = $this->CorporateActivationManagement->addCAMData($camInsertData)) {
6838                            $this->log(__METHOD__ . ' Failed to save corporate activation management data. --> ' . json_encode($camInsertData) . ' -- ' . json_encode($data), $logFileName);
6839                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save corporate activation management data.', $data);
6840                            return ;
6841                        }
6842                        $camlInsertData['cam_id'] = $camRes['id'];
6843                        $camlInsertData['transaction_type'] = 1; // add
6844                    }
6845
6846                    $camlInsertData = $camRes['CorporateActivationManagement'];
6847                    $camlInsertData['cam_id'] = $camlInsertData['id'];
6848                    $camlInsertData['transaction_type'] = 2; // update
6849                    unset($camlInsertData['id']);
6850                    unset($camlInsertData['created']);
6851                    unset($camlInsertData['modified']);
6852                    unset($camlInsertData['created_ip']);
6853                    unset($camlInsertData['modified_ip']);
6854
6855                    if (!$this->CorporateActivationManagementLog->addLog($camlInsertData)) {
6856                        $this->log(__METHOD__ . ' Failed to add corporate activation management log. --> ' . json_encode($camUpdateData) . ' -- ' . json_encode($data), $logFileName);
6857                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to add corporate activation management log.', $data);
6858                        return ;
6859                    }
6860
6861                    $isResume = $this->CorporateActivationManagementLog->isResume($userId);
6862                    $corpCat = $this->CorporateCategory->getDataById($corporateId);
6863                    $corpCat = isset($corpCat['CorporateCategory']) ? $corpCat['CorporateCategory'] : [];
6864                    $mtPassword = null; // mail template password
6865                    if (isset($ptpp['fromCron'])) {
6866                        if ($isResume) {
6867                            $templateId = isset($corpCat['resumption_template_id']) ? $corpCat['resumption_template_id'] : Configure::read('site_in_mail.resume_corporate_mail');
6868                        } else {
6869                            $templateId = isset($corpCat['usage_start_template_id']) ? $corpCat['usage_start_template_id'] : Configure::read('site_in_mail.usage_start_corporate_mail');
6870                        }
6871                    } else {
6872                        if ($isResume) {
6873                            $templateId = isset($corpCat['resume_now_template_id']) ? $corpCat['resume_now_template_id'] : Configure::read('site_in_mail.resume_corporate_mail');
6874                        } else {
6875                            $templateId = isset($corpCat['registration_template_id']) ? $corpCat['registration_template_id'] : Configure::read('site_in_mail.new_corporate_mail');
6876                            if ($camlInsertData['temporary_pw_flg']) {
6877                                $mtPassword = myTools::randStringWithSpecialChar(16);
6878    
6879                                // update user's password
6880                                if (!$this->User->updateUserById(['userData' => ['password' => Security::hash($mtPassword, null, true)], 'id' => $userId])) {
6881                                    $this->log(__METHOD__ . ' Failed to update user password. --> ' . json_encode($mtPassword) . ' -- ' . json_encode($data), $logFileName);
6882                                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update user password.', $data);
6883                                    return ;
6884                                }
6885                            }
6886                        }
6887                    }
6888
6889                    $corporateTypes = Configure::read('corporate_type_arr');
6890                    $mailData = [
6891                        'corporate_plan_type' => $corporateTypes[$corporateId],
6892                        'nickname' => $userData['nickname'],
6893                        'email' => $userData['email'],
6894                        'password' => $mtPassword
6895                    ];
6896
6897                    // send mail
6898                    myMailer::sendTemplateMail($templateId, $mailData['email'], $mailData, [], 'User');
6899                    
6900                }
6901
6902                // NJ-23781- update individual_card_fail_flg : success
6903                $updateIndividualCardFlgParams['individual_card_fail_flg'] = 0;
6904                $res_update_card_fail_flg = $this->update_card_fail_flg($updateIndividualCardFlgParams);
6905
6906                $ptStatus = 1;
6907
6908            // kickback result is NG
6909            } else {
6910                $nativeOptionChanged = $callanOptionChanged = 0;
6911
6912                if (
6913                    $formType != Configure::read('payment_credit_receivable') &&
6914                    $formType != Configure::read('payment_credit_appreciation_receivable') &&
6915                    $formType != Configure::read('corporate_credit_card_registration') &&
6916                    $formType != Configure::read('payment_credit_textbook_purchase') &&
6917                    $formType != Configure::read('payment_credit_coin_purchase') &&
6918                    $formType != Configure::read('payment_prepaid_corporate_light_member_lesson') &&
6919                    $formType != Configure::read('payment_company_credit_corporate_light_lesson') &&
6920                    $formType != Configure::read('payment_credit_change') &&
6921                    $formType != Configure::read('payment_native_option_join') &&
6922                    $formType != Configure::read('payment_callan_option_join') &&
6923                    $formType != Configure::read('payment_native_option_monthly_payment') &&
6924                    $formType != Configure::read('payment_callan_option_monthly_payment') &&
6925                    $settlementType != $settlementTypes['force_charge_payment'] &&
6926                    $settlementType != $settlementTypes['lesson_fee_payment'] &&
6927                    isset($userData['corporate_id']) && isset($userData['payment_plan_id'])
6928                ) {
6929                    $userUpdate = array(
6930                        'fail_flg' => 1,
6931                        'counseling_attended_flg' => 1,
6932                        'charge_flg' => 0,
6933                        'allow_appreciation_flg' => 0,
6934                        'show_appreciation_flg' => 0,
6935                        'next_charge_date' => NULL
6936                    );
6937
6938                    // if card_registration
6939                    if ($logFileName == 'card_registration') {
6940                        $userUpdate['status'] = 1;
6941                    }
6942
6943                    $this->User->validate = array();
6944                    if (!$this->User->read(array_keys($userUpdate), $userId)) {
6945                        $this->log(__METHOD__ . ' User does not exist. --> ' . json_encode($userData), $logFileName);
6946                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'User does not exist.', $data);
6947                        return ;
6948                    }
6949
6950                    // set native option to 0 if individual premium or standard user
6951                    $userUpdate['native_option'] = 0;
6952                    $userUpdate['unli_native_personal_card_flg'] = 0;
6953                    if (isset($userData['native_option']) && $userData['native_option']) {
6954                        $userUpdate['native_option_cancellation_time'] = date("Y-m-d H:i:s");
6955                        $nativeOptionChanged = 1;
6956                    }
6957
6958                    // cancel native option payment
6959                    $this->CorporatesPaymentReceivable->updateAll(
6960                        array(
6961                            'status' => 2,
6962                            'modified' => "'" . date("Y-m-d H:i:s") . "'"
6963                        ),
6964                        array(
6965                            'user_id' => $userId,
6966                            'type' => $this->CorporatesPaymentReceivable->typeCorporateNativeOptionMonthly,
6967                            'status' => 0
6968                        )
6969                    );
6970
6971                    // set callan option to 0 if individual premium or standard user
6972                    $userUpdate['callan_option'] = 0;
6973                    $userUpdate['unli_callan_personal_card_flg'] = 0;
6974                    if (isset($userData['callan_option']) && $userData['callan_option']) {
6975                        $userUpdate['callan_option_cancellation_time'] = date("Y-m-d H:i:s");
6976                        $callanOptionChanged = 1;
6977                    }
6978                    // cancel callan option payment
6979                    $this->CorporatesPaymentReceivable->updateAll(
6980                        array(
6981                            'status' => 2,
6982                            'modified' => "'" . date("Y-m-d H:i:s") . "'"
6983                        ),
6984                        array(
6985                            'user_id' => $userId,
6986                            'type' => $this->CorporatesPaymentReceivable->typeCorporateCallanOptionMonthly,
6987                            'status' => 0
6988                        )
6989                    );
6990
6991                    $this->User->validate = array();
6992                    if (!$this->User->read(array_keys($userUpdate), $userId)) {
6993                        $this->log(__METHOD__ . ' User does not exist. --> ' . json_encode($userData), $logFileName);
6994                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'User does not exist.', $data);
6995                        return ;
6996                    }
6997
6998                    $this->User->set($userUpdate);
6999                    if (!$this->User->save()) {
7000                        $this->log(__METHOD__ . ' Failed to update user data. ' . json_encode($userUpdate), $logFileName);
7001                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update user data.', $data);
7002                        return ;
7003                    }
7004
7005                    // update user who join in ContinuationCampaign to fail status - 3
7006                    $this->ContinuationCampaign->setFailedUser(array(
7007                        'user_id' => $userId
7008                    ));
7009
7010                }
7011
7012                $individualUserUpdate = [];
7013                // set error code
7014                $data['error_code'] = Configure::read('zeus.error.ng_return');
7015                $data['formType'] = $formType;
7016
7017                if ($usingCompanyCard) {
7018                    $data['user_id'] = $userId;
7019                    $data['sendid'] = $corporateId;
7020                }
7021
7022                if (!$this->_error_log_set($data, $ptpp)) {
7023                    $this->log(__METHOD__ . ' Failed to save payment data. ' . json_encode($userUpdate), $logFileName);
7024                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data.', $data);
7025                    return ;
7026                }
7027
7028                if ($nativeOptionPayment > 0 && $formType != Configure::read('payment_native_option_join')) {
7029                    $data['formType'] = Configure::read('payment_native_option_monthly_payment');
7030                    $ptpp['paymentAmount'] = $nativeOptionPayment;
7031                    if ($userData['unli_native_personal_card_flg'] == 1) {
7032                        $updateIndividualCardFlgParams['individual_card_fail_flg'] = 0;
7033                        $individualUserUpdate['unli_native_personal_card_flg'] = 0;
7034                        $individualUserUpdate['native_option'] = 0;
7035                        $individualUserUpdate['callan_option'] = 0;
7036                        
7037                        $nativeOptionChanged = 1;
7038                    }
7039                    if (!$this->_error_log_set($data, $ptpp)) {
7040                        $this->log(__METHOD__ . ' Failed to save payment data. ' . json_encode($userUpdate), $logFileName);
7041                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data.', $data);
7042                        return ;
7043                    }
7044                }
7045
7046                if ($callanOptionPayment > 0 && $formType != Configure::read('payment_callan_option_join')) {
7047                    $data['formType'] = Configure::read('payment_callan_option_monthly_payment');
7048                    $ptpp['paymentAmount'] = $callanOptionPayment;
7049                    if ($userData['unli_callan_personal_card_flg'] == 1) {
7050                        $updateIndividualCardFlgParams['individual_card_fail_flg'] = 0;
7051                        $individualUserUpdate['unli_callan_personal_card_flg'] = 0;
7052                        $individualUserUpdate['native_option'] = 0;
7053                        $individualUserUpdate['callan_option'] = 0;
7054
7055                        $callanOptionChanged = 1;
7056                    }
7057                    if (!$this->_error_log_set($data, $ptpp)) {
7058                        $this->log(__METHOD__ . ' Failed to save payment data. ' . json_encode($userUpdate), $logFileName);
7059                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data.', $data);
7060                        return ;
7061                    }
7062                }
7063
7064                $this->User->validate = array();
7065                if (!$this->User->read(array_keys($individualUserUpdate), $userId)) {
7066                    $this->log(__METHOD__ . ' User does not exist. --> ' . json_encode($userData), $logFileName);
7067                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'User does not exist.', $data);
7068                    return ;
7069                }
7070
7071                $this->User->set($individualUserUpdate);
7072                if (!$this->User->save()) {
7073                    $this->log(__METHOD__ . ' Failed to update user data. ' . json_encode($individualUserUpdate), $logFileName);
7074                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update user data.', $data);
7075                    return ;
7076                }
7077
7078                // NJ-23781- update individual_card_fail_flg : fail
7079                $res_update_card_fail_flg = $this->update_card_fail_flg($updateIndividualCardFlgParams);
7080
7081                $ptStatus = 2; // error;
7082
7083                // log user option changes
7084                $optionLogParams = [
7085                    'user_id' => $userData['id'],
7086                    'platform' => Configure::read('platform.pclp'),
7087                    'status' => 3, // unsubscribed
7088                    'controller_name' => $this->request->params['controller'],
7089                    'action_name' => $this->request->params['action'],
7090                    'user_type' => 0, // user
7091                    'option_before' => 1,
7092                    'option_after' => '', // turn off
7093                    'option_after_name' => '', // turn off
7094                    'payment_plan_id' => $userData['payment_plan_id'],
7095                ];
7096
7097                if ($nativeOptionChanged) {
7098                    $optionLogParams['option_before_name'] = 'Native Unlimited Option';
7099                    $optionLogParams['option_type'] = 1;
7100                    ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
7101                }
7102
7103                if ($callanOptionChanged) {
7104                    $optionLogParams['option_before_name'] = 'Callan Unlimited Option';
7105                    $optionLogParams['option_type'] = 2;
7106                    ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
7107                }
7108                
7109            }
7110
7111            // log membership status change
7112            if (isset($ptpp['statusBefore']) && isset($ptpp['statusAfter']) && isset($ptpp['platform'])) {
7113                $statusAfter = $kbResultOk ? $ptpp['statusAfter'] : myTools::getCorporateUserMembershipStatusName(UserTable::getEngMembershipTypeData(), $paymentPlanId, true);
7114
7115                $currentUser = $this->User->find('first', array(
7116                    'fields' => array('User.parent_id', 'User.currency_code', 'User.payment_plan_id'),
7117                    'conditions' => array('User.id' => $userId),
7118                    'recursive' => -1
7119                ));
7120
7121                $currency_after_payment = $currentUser['User']['currency_code'];
7122                $plan_id_after_payment = $currentUser['User']['payment_plan_id'];
7123                $parentIdPay = $currentUser['User']['parent_id'];
7124                $is_cron_pay = 0;
7125                if (php_sapi_name() == 'cli'){
7126                    $is_cron_pay = 1;
7127                } 
7128                $usclData = array(
7129                    'user_id' => $userId,
7130                    'platform' => $ptpp['platform'] ?? '',
7131                    'card_company_before' => $userData['card_company'],
7132                    'status_before' => $ptpp['statusBefore'],
7133                    'status_after' => $statusAfter,
7134                    'controller_name' => $this->request->params['controller'],
7135                    'action_name' => $this->request->params['action'],
7136                    'parent_id' => $parentIdPay,
7137                    'is_cron' => $is_cron_pay,
7138                    'currency_before' => $currency_before_payment,
7139                    'currency_after' => $currency_after_payment,
7140                    'payment_plan_id_before' => $plan_id_before_payment,
7141                    'payment_plan_id_after' => $plan_id_after_payment
7142                );
7143
7144                // save user change membership status
7145                if (!$this->UserStatusChangeLog->saveLog($usclData)) {
7146                    $this->log(__METHOD__ . ' Failed to save user status change log data. --> ' . json_encode($paymentData), $logFileName);
7147                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save user status change log data.', $data);
7148                    return;
7149                }
7150            }
7151
7152            // update payment transaction
7153            $this->updatePaymentTransaction(array(
7154                'id' => $ptData['id'],
7155                'fields' => array(
7156                    'status' => $ptStatus,
7157                    'response_text' => array('zp_kickback' => $data)
7158                ),
7159                'logFileName' => 'debug'
7160            ));
7161
7162
7163            // send event to adjust
7164            if ($kbResultOk) {
7165                $adjustParams = array(
7166                    'formType' => $formType,
7167                    'statusBefore' => isset($ptpp['statusBefore']) ? $ptpp['statusBefore'] : null,
7168                    'userId' => $userId,
7169                    'idfa' => $userData['idfa']
7170                );
7171                UserTable::sendEventToAdjust($adjustParams);
7172            }
7173        }
7174
7175        return;
7176    }
7177
7178    /**
7179     * @api {get} /payment/update_card_fail_flg/:user_data/:form_type/:individual_card_fail_flg update_card_fail_flg
7180     * @apiName update_card_fail_flg
7181     * @apiGroup Payment
7182     * @apiDescription This endpoint is used to update card fail flag.
7183     * 
7184     * @apiParam {String} user_data User data. null if not provided
7185     * @apiParam {String} form_type Form type. null if not provided
7186     * @apiParam {Number} individual_card_fail_flg Individual card fail flag. 0 if not provided
7187     * 
7188     * @apiSuccess {Boolean} true Returns true if successful
7189     * 
7190     * @apiError {Boolean} false Returns false if failed
7191     * 
7192     * @apiSuccessExample Success Response:
7193     * true
7194     * 
7195     * @apiErrorExample Error Response:
7196     * false
7197     */
7198    public function update_card_fail_flg($params = []){
7199        $user_data = !empty($params['user_data']) ? $params['user_data'] : null;
7200        $form_type = !empty($params['form_type']) ? $params['form_type'] : null;
7201        $individual_card_fail_flg = !empty($params['individual_card_fail_flg']) ? $params['individual_card_fail_flg'] : 0;
7202        
7203        if(!$user_data || !$form_type){return false;}
7204
7205        $userObj = new UserTable($user_data);
7206
7207        if(in_array($userObj->getMembershipTypeIndex(), Configure::read('corp_personal_card_payment_valid_memberships'))
7208            && in_array($form_type,
7209            array(
7210                Configure::read('payment_credit_textbook_purchase'),
7211                Configure::read('payment_credit_coin_purchase'),
7212                Configure::read('payment_native_option_join'),
7213                Configure::read('payment_credit_receivable'),
7214                Configure::read('payment_credit_appreciation_receivable'),
7215                Configure::read('corporate_credit_card_registration'),
7216                Configure::read('corp_user_change_personal_card')
7217            ))
7218        ){
7219            // - update individual_card_fail_flg
7220            $this->UsersDetail->updateCorpIndividualCardFlg(['user_id' => $userObj->id, 'individual_card_fail_flg' => $individual_card_fail_flg]);
7221            return true;
7222        }
7223
7224        return false;
7225    }
7226
7227    // NJ-69193 ~ private to public to easily access via unit test
7228    public function _error_log_set($data = array(), $paymentParams = array()) {
7229        // set the variables
7230        $userId = isset($data['user_id']) ? $data['user_id'] : 0;
7231        $money = isset($paymentParams['paymentAmount']) ? $paymentParams['paymentAmount'] : ( isset($_GET['money']) ? $_GET['money'] : 0 );
7232        $sendId = isset($data['sendid']) ? $data['sendid'] : 0;
7233        $cardCompany = isset($data['metadata']['card_company']) ? $data['metadata']['card_company'] : Configure::read('card_company.zeus');
7234        $formType = isset($data['formType']) ? $data['formType'] : 0;
7235        $result = array();
7236
7237        if ($userId && !$sendId) {
7238            $sendId = $userId;
7239        } elseif ($sendId && !$userId) {
7240            $userId = $sendId;
7241        }
7242
7243        $paymentType = isset($paymentParams['paymentType']) ? $paymentParams['paymentType'] : null;
7244        $priceId = isset($paymentParams['priceId']) ? $paymentParams['priceId'] : null;
7245        $paymentId = isset($paymentParams['paymentPlanId']) ? $paymentParams['paymentPlanId'] : null;
7246        $currencyCode = isset($paymentParams['currencyCode']) ? $paymentParams['currencyCode'] : Configure::read('currency_jpy');
7247        $discounted_amount = isset($paymentParams['discounted_amount']) ? $paymentParams['discounted_amount'] : 0;
7248
7249        // Check receivable type
7250        $cronDateRun = date("Y-m-d H:i:s");
7251        $receivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun);
7252        $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('appreciation_data.payment_element_type'));
7253        $liveReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.live'));
7254        $receivableFormTypeArr = array( Configure::read('payment_credit_receivable') );
7255        
7256        if( in_array( $formType, $receivableFormTypeArr ) ) {
7257            // Appreciation 
7258            if( $appreciationReceivable > 0 ) {
7259                $this->Payment->create();
7260                $this->Payment->set(array(
7261                    'user_id' => $userId,
7262                    'type_id' => 1,
7263                    'pay_kbn' => 1,
7264                    'form_type' => Configure::read('payment_credit_appreciation_receivable'),
7265                    'reference_id' => $sendId,
7266                    'amount' => $appreciationReceivable,
7267                    'card_company' => $cardCompany,
7268                    'param1' => json_encode($data),
7269                    'param2' => "error:" . $data['error_code'],
7270                    'currency_code' => $currencyCode,
7271                    'price_id' => $priceId,
7272                    'payment_id' => $paymentId,
7273                    'payment_type' => $paymentType,
7274                    'discounted_amount' => $discounted_amount
7275                ));
7276                $result[$formType][] = $this->Payment->save();
7277            }
7278
7279            // Live receivable 
7280            if( $liveReceivable > 0 ) {
7281                $this->Payment->create();
7282                $this->Payment->set(array(
7283                    'user_id' => $userId,
7284                    'type_id' => 1,
7285                    'pay_kbn' => 1,
7286                    'form_type' => Configure::read('payment_live_lesson_receivable'),
7287                    'reference_id' => $sendId,
7288                    'amount' => $liveReceivable,
7289                    'card_company' => $cardCompany,
7290                    'param1' => json_encode($data),
7291                    'param2' => "error:" . $data['error_code'],
7292                    'currency_code' => $currencyCode,
7293                    'price_id' => $priceId,
7294                    'payment_id' => $paymentId,
7295                    'payment_type' => $paymentType,
7296                    'discounted_amount' => $discounted_amount
7297                ));
7298                $res = $this->Payment->save();
7299
7300                if (!$res) {
7301                    CakeLog::debug(__METHOD__ . 'Error : saving live receivable -> params' . json_encode([$data, $paymentParams]));
7302                }
7303                $result[$formType][] = $res;
7304            }        
7305
7306            // Reservation
7307            if( $receivable > 0 ) {
7308                $this->Payment->create();
7309                $this->Payment->set(array(
7310                    'user_id' => $userId,
7311                    'type_id' => 1,
7312                    'pay_kbn' => 1,
7313                    'form_type' => Configure::read('payment_credit_receivable'),
7314                    'reference_id' => $sendId,
7315                    'amount' => $receivable,
7316                    'card_company' => $cardCompany,
7317                    'param1' => json_encode($data),
7318                    'param2' => "error:" . $data['error_code'],
7319                    'currency_code' => $currencyCode,
7320                    'price_id' => $priceId,
7321                    'payment_id' => $paymentId,
7322                    'payment_type' => $paymentType,
7323                    'discounted_amount' => $discounted_amount
7324                ));
7325                $result[$formType][] = $this->Payment->save();
7326            }
7327
7328        } else {
7329            try {
7330                if( $money > 0 ) {
7331                    // save new payment row
7332                    $this->Payment->create();
7333                    $this->Payment->set(array(
7334                            'user_id' => $userId,
7335                            'type_id' => 1,
7336                            'pay_kbn' => 1,
7337                            'form_type' => $formType,
7338                            'reference_id' => $sendId,
7339                            'amount' => $money,
7340                            'card_company' => $cardCompany,
7341                            'param1' => json_encode($data),
7342                            'param2' => "error:" . $data['error_code'],
7343                            'currency_code' => $currencyCode,
7344                            'price_id' => $priceId,
7345                            'payment_id' => $paymentId,
7346                            'payment_type' => $paymentType,
7347                            'discounted_amount' => $discounted_amount
7348                    ));
7349    
7350                    $result[$formType] = $this->Payment->save();
7351    
7352                    $annualDiscountOption = isset($paymentParams['annualDiscountOption']) ? $paymentParams['annualDiscountOption'] : [];
7353                    // check if user plan has annual discount option
7354                    if ($annualDiscountOption) {
7355                        // set data for discount option settlement history
7356                        $doshData = [
7357                            'user_id' => $userId,
7358                            'discount_option_term_id' => $annualDiscountOption['discount_option_term_id'],
7359                            'discount_option_id' => $annualDiscountOption['discount_option_id'],
7360                            'payment_id' => $this->Payment->id,
7361                            'discount_option_price_id' => $annualDiscountOption['discount_option_price_id'],
7362                            'payment_id' => $this->Payment->id,
7363                            'event' => $annualDiscountOption['dosh_event'],
7364                            'amount' =>  $annualDiscountOption['amount'] ?? 0,
7365                            'currency_code' => $currencyCode,
7366                            'type' => isset($annualDiscountOption['dosh_type']) ? $annualDiscountOption['dosh_type'] : null,
7367                            'status' => $annualDiscountOption['dosh_status'],
7368                            'settlement_status' => 0 // failed
7369                        ];
7370    
7371                        // create discount option settlement history
7372                        if (!$res = $this->DiscountOptionsSettlementHistory->createHistory($doshData)) {
7373                        }
7374    
7375                        $result[$formType][] = $res;
7376                    }
7377                }
7378            } catch (\Throwable $th) {
7379                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'try-catch - Failed to create payment receivable.', [
7380                    'data' => $data,
7381                    'payment_transaction' => $paymentParams,
7382                    'error' => $th->getMessage()
7383                ]);
7384            } catch(\Exception $e) {
7385                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'try-catch - Failed to create payment receivable.', [
7386                    'data' => $data,
7387                    'payment_transaction' => $paymentParams,
7388                    'error' => $e->getMessage()
7389                ]);
7390            }
7391        }
7392    
7393        return $result;
7394        
7395    }
7396    /**
7397     * @api {post} /payment/free_digest_member_t_start/:param free_digest_member_t_start
7398     * @apiName free_digest_member_t_start
7399     * @apiGroup Payment
7400     * @apiDescription This endpoint is used to start free digest member.
7401     * 
7402     * @apiParam {String} param Parameter. FALSE if not provided
7403     * 
7404     * @apiBody {String} card_brand Card brand
7405     * 
7406     * @apiSuccess {View} Redirect Redirects to {{ENV}}/payment/payment_credit_retry_form
7407     * 
7408     * @apiError {Boolean} err Returns true if there is error
7409     * 
7410     * @apiSuccessExample Success Response:
7411     * Redirects to {{ENV}}/payment/payment_credit_retry_form
7412     * 
7413     * @apiErrorExample Error Response:
7414     * true
7415     * 
7416     * @apiSampleRequest off
7417     */
7418    public function free_digest_member_t_start($param = FALSE){
7419        $this->checkUser(Configure::read('payment_credit_retry'));
7420        $err = false;
7421        if ($this->request->is('post')) {
7422            if (!isset($this->request->data['card_brand'])) {
7423                $err = true;
7424            } else {
7425                $this->redirect(myTools::getUrl() . '/payment/payment_credit_retry_form/' . $this->request->data['card_brand']);
7426            }
7427        }
7428        $this->set('hide_err', $err);
7429    }
7430
7431    /**
7432     * @api {post} /payment/coupon_form coupon_form
7433     * @apiName coupon_form
7434     * @apiGroup Payment
7435     * @apiDescription This endpoint is used to handle the submission of a complimentary code form.
7436     * 
7437     * @apiSuccess {Boolean} status The status of the request
7438     * @apiSuccess {String} url The URL to redirect to
7439     * 
7440     * @apiError {Boolean} status The status of the request.
7441     * @apiError {String} url The URL to redirect to if the request is unsuccessful.
7442     * 
7443     * @apiSuccessExample {json} Success Response:
7444     * {
7445     *         "status": true,
7446     *         "url": "payment/coupon_code"
7447     * }
7448     * 
7449     * @apiErrorExample {json} Error Response:
7450     * {
7451     *         "status": false,
7452     *         "url": null
7453     * }
7454     */
7455    public function coupon_form(){
7456        $this->response->disableCache();
7457        # Preventing from rendering the 404 not found page error
7458        $this->autoRender = false;
7459
7460        # response data
7461        $response = array(
7462            "status" => false, 
7463            "url" => null
7464        );
7465
7466        # Get register2 data from set session in create_account
7467        $data = $this->Session->read('register2');        
7468
7469        # Get user information
7470        $this->User->openDBReplica();
7471        $data = $this->User->find("first",array(
7472                "conditions" => array('User.id' => $this->Auth->User('id')),
7473                "fields" => array(
7474                    'User.id',
7475                    'User.currency_code',
7476                    'User.payment_plan_id',
7477                    'User.price_id'
7478                ),
7479                "recursive" => -1
7480            )
7481        );
7482        $this->User->closeDBReplica();
7483
7484        $this->PaymentPlanPrice->openDBReplica();
7485        $ccPayment = $this->PaymentPlanPrice->getPaymentData(array(
7486            "currencyCode" => $data['User']["currency_code"],
7487            "paymentPlanId" => Configure::read('payment_plans.complimentary_plan')
7488        ));
7489        $this->PaymentPlanPrice->closeDBReplica();
7490
7491        # check if the request is not post
7492        if (!$this->request->is("post")) {
7493            $response["status"] = false;
7494            return json_encode($response);
7495        }
7496
7497        # get post data
7498        $post = $this->request->data;
7499        $complimentaryCode = trim($post['complimentary_code']);
7500
7501        # check if the post is an empty
7502        if($complimentaryCode === ""):
7503            $response["status"] = true;
7504            return json_encode($response);
7505        endif;
7506
7507        # check if the array is empty on the paymentPlanPrice
7508        if(empty($ccPayment)):
7509            $response["status"] = false;
7510            return json_encode($response);
7511        endif;
7512        
7513        $ccUpdateFlg = $this->User->checkComplimentaryCodeAvailableAndSave(array(
7514            "complimentaryCode" => $complimentaryCode,
7515            "userId" => $data['User']["id"]
7516        ));
7517
7518        # set complimentary error to true if not save
7519        if (!$ccUpdateFlg) {
7520            $response["status"] = false;
7521            return json_encode($response);
7522        } 
7523
7524        $paymentPlanId = (isset($ccPayment['paymentPlanId']) && isset($complimentaryCode)) ? $ccPayment['paymentPlanId'] : null;
7525        $priceId = (isset($ccPayment['priceId']) && isset($complimentaryCode)) ? $ccPayment['priceId'] : null;
7526
7527        if (!isset($ccUpdateFlg) || (isset($ccUpdateFlg) && $ccUpdateFlg)) {
7528
7529            $this->User->openDBReplica();
7530            $dataUpdate = $this->User->find("first",array(
7531                    "conditions" => array('User.id' => $data['User']['id']),
7532                    "fields" => array(
7533                        "User.complimentary_code"
7534                    ),
7535                    "recursive" => -1
7536                )
7537            );
7538            $this->User->closeDBReplica();
7539            $userUpdate = $dataUpdate['User'];        
7540            if (isset($userUpdate["complimentary_code"]) && $userUpdate["complimentary_code"] != $complimentaryCode) {
7541                $this->ComplimentaryCode->updateAll(
7542                    array("account_used_cnt" => "account_used_cnt - 1"),
7543                    array("code" => $complimentaryCode)
7544                );
7545            }
7546
7547            if (!empty($complimentaryCode)) {                
7548                $coinData = array(
7549                    "status" => false,
7550                    "ref" => $data['User']["id"]
7551                );
7552
7553                $this->Session->write("coinReadRefStatus", $coinData);
7554
7555                $response["status"] = true;
7556                $response["url"] = "payment/coupon_code";
7557                $this->Session->write('complimentaryToPlan', true);
7558
7559                # update the complimentary
7560                $updateUserData = array(
7561                    'user_id' => $data['User']['id'],
7562                    'complimentary_code' => $complimentaryCode,
7563                    'payment_plan_id' => $paymentPlanId,
7564                    'price_id' => $priceId,                
7565                );
7566
7567                $this->User->regist($updateUserData);        
7568            }
7569        }
7570        return json_encode($response);
7571    }
7572
7573    /**
7574     * @api {get} /:language/payment/payment_credit_register payment_credit_register()
7575     * @apiName payment_credit_register
7576     * @apiGroup Payment
7577     * @apiDescription This function is used to display the payment credit register page.
7578     * 
7579     * @apiParam {String} language Language code of the user
7580     * 
7581     * @apiSuccess {View} Render Displays the payment credit register page.
7582     * 
7583     * @apiError {View} Redirect Redirects to {{ENV}}/ if monthly price data does not exist.
7584     * @apiError {View} Redirect Redirects to {{ENV}}/account/sms_authentication if user does not have phone number.
7585     * 
7586     * @apiSuccessExample Success Response:
7587     * Displays the payment credit register page.
7588     * 
7589     * @apiErrorExample Error Response No monthly price data:
7590     * Redirects to {{ENV}}/
7591     * 
7592     * @apiErrorExample Error Response No phone number:
7593     * Redirects to {{ENV}}/account/sms_authentication
7594     * 
7595     * @apiSampleRequest off
7596     */
7597    public function payment_credit_register() {
7598        $this->blockWithdrawnSapuriToS();
7599        $this->disablePageForSapuri();
7600        $this->checkUser(Configure::read('payment_credit_authentication'));
7601
7602        $this->loadModel('PurchaseCoinPrice');
7603        $this->set('bonusCoin', myTools::formatAmount($this->PurchaseCoinPrice->getSignupBonusCoin($this->sharedUserData['User']['currency_code'])));
7604
7605        //- NJ-23812 : redirect to sms authentication 
7606        $_userid = $this->Auth->user('id');
7607        $_user = $this->sharedUserData['User'];
7608        
7609        // NJ-68818: check if payment was charged after challenge already
7610        $this->checkIfChargedAfterChallenge($_userid, 'register');
7611
7612        #chocotto plan data
7613        $chocottoPlanData = $this->PaymentPlanPrice->getPaymentData(array(
7614            'currencyCode' => $_user['currency_code'],
7615            'paymentPlanId' => Configure::read('payment_plans.chocotto_plan'),
7616            'logFileName' => $logFileName ?? 'card_register'
7617        ));
7618
7619        // - set chocotto plan price
7620        $this->set('chocottoMonthlyPrice',$chocottoPlanData['fAmount']);
7621        $this->set('chocottoMonthlyPriceNoTax', myTools::formatAmount($chocottoPlanData['amountConstTaxDeducted']));
7622
7623        //- NJ-27262 : check private page from chocotto
7624        $this->set('enableChocottoPlan', $this->Cookie->read('chocotto_lp'));
7625
7626        //NJ-3882 Require SMS Authentication before Credit Card Registration
7627        $this->PhoneVerifyCheckLog->openDBReplica();
7628        $countTotalVerify = $this->PhoneVerifyCheckLog->find('count',array(
7629            'conditions'=> array(
7630                'user_id' => $this->Auth->user('id'),
7631                'status' => 0
7632            )
7633        ));
7634        $this->PhoneVerifyCheckLog->closeDBReplica();
7635        
7636        if (
7637            empty($_user['facebook_id']) && 
7638            empty($_user['google_id']) &&
7639            empty($_user['line_id']) &&
7640            empty($_user['apple_id']) &&
7641            empty($_user['sms_through_flg']) && 
7642            empty($_user['phone_number']) 
7643        ) {
7644            $this->Session->write('check-step1', true);
7645            $this->Session->write('register_user_id', $_userid);
7646            $this->Session->write('register2', array('user_id' => $_userid));
7647            if (empty($_user['corporate_id'])) { // NJ-36129 Bug fix: Skip SMS Auth for Corporate Users
7648                return $this->redirect('/account/sms_authentication');
7649            }
7650        }
7651
7652        $monthlyPrice ??= '';
7653        
7654        // get monthly price for premium
7655        $pDataDisplay = $this->PaymentPlanPrice->getPaymentData(array(
7656            'currencyCode' => $_user['currency_code'],
7657            'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
7658            'logFileName' => 'card_reregister'
7659        ));
7660
7661        // return to top top page if monthly price data does not exist
7662        if (!$pDataDisplay) {
7663            return $this->redirect('/');
7664        }
7665
7666        $this->set('amount', $pDataDisplay['amount']);
7667        $this->set('monthlyPrice', myTools::formatAmount($pDataDisplay['amount']));
7668        $this->set('monthylyPriceNoTax', myTools::formatAmount($pDataDisplay['amountConstTaxDeducted']));
7669        $this->set('monthlyPriceSymbol',myTools::getCurrencySymbol($_user['currency_code']));
7670
7671        // redirect to zeus if currency is equals to jpy
7672        if ($this->sharedUserData['User']['currency_code'] == Configure::read('default.user_currency')) {
7673            $this->zeus_credit_register($pDataDisplay);
7674        // redirect to wp
7675        } else {
7676            $this->wp_credit_register();
7677        }
7678    
7679        $this->CountryCode->openDBReplica();
7680        $countryCodes = $this->CountryCode->find('all',array(
7681            'fields' => array(
7682                'code',
7683                'country_name'
7684            ),
7685            'order' => 'country_name ASC'
7686        ));
7687        $this->CountryCode->closeDBReplica();
7688        $this->set('countryCodes',$countryCodes);
7689        
7690        $user = new UserTable($this->sharedUserData['User']);
7691        $users_detail = new UsersDetailTable($this->sharedUserData['UsersDetail']);
7692        $this->set('users_detail', $users_detail);
7693        $this->set('user', $user);
7694        $this->set('countTotalVerify',$countTotalVerify);
7695        $this->set('amount', $monthlyPrice);
7696        if ($this->RequestHandler->isMobile()) {
7697            if (!$countTotalVerify &&
7698                !$user->facebook_id &&
7699                !$user->google_id &&
7700                !$user->line_id &&
7701                !$user->apple_id &&
7702                !$user->sms_through_flg
7703            ) {
7704                return $this->redirect('/account/sms_authentication');
7705            }
7706        }
7707        
7708        $userData = $this->sharedUserData['User'];
7709        // NJ-30828: set view to display user's paypal email
7710        $this->setPaypalUser($userData);
7711
7712        // NJ-36129
7713        $sp = Configure::read('registration_platforms.sp');
7714        $pc = Configure::read('registration_platforms.pc');
7715        $platformId = $this->RequestHandler->isMobile() ? $sp : $pc;
7716        $stepKey = Configure::read('registration_steps.credit_card_registration');
7717
7718        $saveStepParams = array(
7719            'user_id' => $_userid,
7720            'step_key' => $stepKey,
7721            'platform' => $platformId
7722        );
7723
7724        ClassRegistry::init('UserRegistrationStatus')->saveStep($saveStepParams);
7725        
7726    }
7727
7728    private function zeus_credit_register($premiumPlanData = []) {
7729        $user = $this->sharedUserData['User'];
7730        $formType = Configure::read('payment_credit_authentication');
7731        $logFileName = 'card_reregister';
7732
7733        // get free trial payment data
7734        $freeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
7735            'currencyCode' => $user['currency_code'],
7736            'paymentPlanId' => Configure::read('payment_plans.free_trial'),
7737            'logFileName' => $logFileName
7738        ));
7739
7740        // - NJ-23812 : reset session for paypal credit register data
7741        if ($this->Session->read('paypalPaymentCreditRegisterData')){
7742            $this->Session->delete('paypalPaymentCreditRegisterData');
7743        }
7744
7745
7746        // - NJ-23812 : reset  
7747        if ($this->Session->read('credit_skip_to_confirmation')){
7748            $this->Session->delete('credit_skip_to_confirmation');
7749        }
7750
7751        if (!$freeTrialData) {
7752            return $this->redirect('/');
7753        }
7754
7755        $annualDiscountOptionData = $this->DiscountOptionsPrice->getPaymentData(['currencyCode' => $user['currency_code'], 'discountOptionId' => Configure::read('discount_option.annual.plan_id')]);
7756        $annualDiscountOptionAmount = $annualDiscountOptionData ? $annualDiscountOptionData['amount'] : 0;
7757        $monthlyPriceWithAnnualDiscount = $premiumPlanData['amount'] - $annualDiscountOptionAmount;
7758        $monthlyPriceWithAnnualDiscountNoTax = $monthlyPriceWithAnnualDiscount / Configure::read('added_tax_percentage');
7759        $monthlyPriceWithAnnualDiscountNoTax = round($monthlyPriceWithAnnualDiscountNoTax);
7760
7761        $this->set('enableAnnualDiscountOption', $annualDiscountOptionData ? true : false);
7762        $this->set('annualDiscountOptionAmount', myTools::formatAmount($annualDiscountOptionAmount));
7763        $this->set('monthlyPriceWithAnnualDiscount', myTools::formatAmount($monthlyPriceWithAnnualDiscount));
7764        $this->set('monthlyPriceWithAnnualDiscountNoTax', myTools::formatAmount($monthlyPriceWithAnnualDiscountNoTax));
7765
7766        // check if post data
7767        if ($this->request->is('post')) {
7768            $data = $this->request->data;
7769
7770            // - check if user selected lite plan (1 = lite , 0 = premium)
7771            $paymentPlanType = (isset($data['ZPaymentFullLogs']['payment_plan_type'])) ? (int) $data['ZPaymentFullLogs']['payment_plan_type'] : 0;
7772
7773            $litefreeTrialData = null;
7774
7775            $_isLitePlanFlg = 0;
7776            $liteFormType = null;
7777            $_isChocottoPlanFlg = 0;
7778            $chocottoFormType = null;
7779
7780            // - if lite plan
7781            if ($paymentPlanType == Configure::read('register_plan_types.light')) {
7782                $_isLitePlanFlg = 1;
7783                $userTable = new UserTable($user);
7784                $membershipTypes = UserTable::getEngMembershipTypeData();
7785                $membershipTypeIndex = $userTable->getMembershipTypeIndex();
7786
7787                // - fetch the lite payment plan 
7788                $litefreeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
7789                    'currencyCode' => $user['currency_code'],
7790                    'paymentPlanId' => Configure::read('payment_plans.light_plan_free'),
7791                    'logFileName' => 'card_reregister'
7792                ));
7793                
7794                // - change the price id and payment plan 
7795                $user['price_id'] = $litefreeTrialData['priceId'];
7796                $user['payment_plan_id'] = $litefreeTrialData['paymentPlanId'];
7797                $user['paymentAmount'] = $litefreeTrialData['amount'];
7798                $user['statusBefore'] = $membershipTypes[$membershipTypeIndex];
7799                $_lightplanFree = Configure::read('membership_type_lightplan_free');
7800                $user['statusAfter'] = $membershipTypes[$_lightplanFree]; // - light plan free
7801
7802                // - set the form type 
7803                $liteFormType = $formType = myTools::getLitePlanUserFormType($litefreeTrialData['paymentPlanId']);
7804
7805                // set transaction error to 1 if failed to create payment transaction
7806                if (!$pt = $this->createPaymentTransaction($formType, $user)) {
7807                    $this->set('transactionError', 1);
7808                }
7809
7810                // - update the payment hash
7811                $data['ZPaymentFullLogs']['paymentHash'] =    $pt['payment_hash'];
7812
7813            //- if chocotto plan
7814            } elseif ($paymentPlanType == Configure::read('register_plan_types.chocotto')) {
7815                $_isChocottoPlanFlg = 1;
7816                $userTable = new UserTable($user);
7817                $membershipTypes = UserTable::getEngMembershipTypeData();
7818                $membershipTypeIndex = $userTable->getMembershipTypeIndex();
7819
7820                // - fetch the chocotto payment plan 
7821                $chocottofreeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
7822                    'currencyCode' => $user['currency_code'],
7823                    'paymentPlanId' => Configure::read('payment_plans.free_trial_chocotto'),
7824                    'logFileName' => 'card_reregister'
7825                ));
7826                
7827                // - change the price id and payment plan 
7828                $user['price_id'] = $chocottofreeTrialData['priceId'];
7829                $user['payment_plan_id'] = $chocottofreeTrialData['paymentPlanId'];
7830                $user['paymentAmount'] = $chocottofreeTrialData['amount'];
7831                $user['statusBefore'] = $membershipTypes[$membershipTypeIndex];
7832                $_chocottoPlanFree = Configure::read('membership_type_chocotto_plan_free');
7833                $user['statusAfter'] = $membershipTypes[$_chocottoPlanFree]; // - chocotto plan free
7834
7835                // - set the form type 
7836                $chocottoFormType = $formType = myTools::getChocottoPlanUserFormType($chocottofreeTrialData['paymentPlanId']);
7837
7838                //- NJ-36141: reset daily lesson time if changed to chocotto plan
7839                $this->UsersDetail->chocottoCampUserDetails($user['id'], true);
7840                
7841                // set transaction error to 1 if failed to create payment transaction
7842                if (!$pt = $this->createPaymentTransaction($formType, $user)) {
7843                    $this->set('transactionError', 1);
7844                }
7845
7846                // - update the payment hash
7847                $data['ZPaymentFullLogs']['paymentHash'] =    $pt['payment_hash'];
7848
7849            // if annual discount option
7850            } elseif ($paymentPlanType == Configure::read('register_plan_types.premium_with_annual_discount_option')) {
7851                // redirect to credit page if annual discount option does not exist or is not enabled
7852                if (!$annualDiscountOptionData) {
7853                    return $this->redirect('/');
7854                }
7855
7856                $annualDiscountOptionData['amount'] = 0; // change amount to 0 since this is a subscription
7857                $annualDiscountOptionData += [
7858                    'dosh_event' => Configure::read('discount_option.dosh_event.annual_discount'),
7859                    'dosh_status' => Configure::read('discount_option.dosh_status.subscription'),
7860                    'option_after_name' => 'Annual Discount Option',
7861                    'option_type' => 3
7862                ];
7863
7864                // update payment transaction (add annual discount option data)
7865                $this->PaymentTransaction->updatePaymentParams(array('paymentHash' => $data['ZPaymentFullLogs']['paymentHash'], 'updateData' => ['discountOption' => $annualDiscountOptionData]));
7866
7867                $data['discountOption'] = $annualDiscountOptionData;
7868            }
7869
7870            // redirect to paypal confirm page if payment gateway selected is paypal
7871            if ($data['payment_gateway_type'] == Configure::read('card_company.paypal')) {
7872                $data['paymentPlanData'] = $freeTrialData;
7873
7874                if ($paymentPlanType == 1) {
7875                    $data['paymentPlanData'] = $litefreeTrialData;
7876                }
7877
7878                $this->Session->write('paypalPaymentCreditRegisterData', $data);
7879                return $this->redirect(myTools::getUrl() . '/payment/paypal_payment_credit_register_confirm');
7880            }
7881
7882            // delete payment gateway type memcache
7883            $this->memcache->delete('creditReregisterPaymentGatewayType_' . $user['api_token']);
7884
7885            $data['ZPaymentFullLogs']['clientip'] = Configure::read('ZEUS_clientip');
7886            $data['ZPaymentFullLogs']['telno'] = Configure::read('credit.default_telno');
7887
7888            if ($this->Session->read('PaymentCreditRegisterInfo')) {
7889                $this->Session->delete('PaymentCreditRegisterInfo');
7890            }
7891            $this->Session->write('PaymentCreditRegisterInfo', $data);
7892
7893            //NJ-13482 Skip Confirmation Page for New Enrollment
7894            //NJ-25522: Skip Confirmation Page if using 3D secure challenge
7895            $zeus3DSecureChallengeFlg = $this->memcache->get('zeus3DSecureChallengeFlg_' . $user['id']);
7896
7897            if (isset($user['id']) && (!$this->isForTrialReenrollment($user['id']) || $zeus3DSecureChallengeFlg)) {
7898                $data = $this->Session->read('PaymentCreditRegisterInfo');
7899                $checkToken = $this->checkToken($data['token']);
7900
7901                if ($checkToken) {
7902                    $this->unsetToken();
7903                    $formType = Configure::read('payment_credit_authentication');
7904                
7905                    if ($_isLitePlanFlg) {
7906                        $formType = $liteFormType;
7907                    }
7908
7909                    if ($_isChocottoPlanFlg) {
7910                        $formType = $chocottoFormType;
7911                    }
7912    
7913                    $referrer = array('controller' => 'Payment', 'action' => 'payment_credit_register');
7914                    $this->z_start($data, $formType, $referrer);
7915                }
7916            }
7917
7918            $this->Session->delete('paypalPaymentCreditRegisterData');
7919
7920            $this->Session->write('credit_skip_to_confirmation',true);
7921
7922            return $this->redirect(myTools::getUrl() . '/payment/payment_credit_register_confirm');
7923
7924        } else {
7925            $data = $this->Session->read('PaymentCreditRegisterInfo');
7926            $this->set('data', $data);
7927        }
7928
7929        // NC-3914
7930        $this->getAndSetCardInfo($user);
7931
7932        // clear previously set tokens and set new token
7933        $this->unsetToken();
7934        $token = md5(uniqid(rand(), true));
7935        $this->Session->write('Payment.token', $token);
7936
7937        $userTable = new UserTable($user);
7938        $membershipTypes = UserTable::getEngMembershipTypeData();
7939        $membershipTypeIndex = $userTable->getMembershipTypeIndex();
7940        
7941        $user['price_id'] = $freeTrialData['priceId'];
7942        $user['payment_plan_id'] = $freeTrialData['paymentPlanId'];
7943        $user['paymentAmount'] = $freeTrialData['amount'];
7944        $user['statusBefore'] = $membershipTypes[$membershipTypeIndex];
7945        $user['statusAfter'] = $membershipTypes[2];
7946
7947        if (isset($annualDiscountOption)) {
7948            $user['discountOption'] = $annualDiscountOption;
7949        }
7950
7951        // set transaction error to 1 if failed to create payment transaction
7952        if (!$pt = $this->createPaymentTransaction($formType, $user)) {
7953            $this->set('transactionError', 1);
7954        }
7955
7956        // ------- NJ-23812 : set support paypal skip from confirmation page 
7957        $sessionPaypalParams = array(
7958            'token' => $token,
7959            'payment_gateway_type' => Configure::read('card_company.paypal'),
7960            'ZPaymentFullLogs' => array(
7961                'paymentHash' => isset($pt['payment_hash']) ? $pt['payment_hash'] : "",
7962                'money' => str_replace('.00', '', $freeTrialData['amount'])
7963            ),
7964            'paymentPlanData' => $freeTrialData
7965        );
7966
7967        $this->Session->write('paypalPaymentCreditRegisterData', $sessionPaypalParams);
7968        
7969        $this->setSupportPayPal($user);
7970        $this->set('token', $token);
7971
7972        $this->set('userApiToken', $this->sharedUserData['User']['api_token']);
7973        $this->set('paypalFlg', true); // use for modal loader
7974
7975        // ----- NJ-23812: end support paypal skip from confirmation page
7976
7977        // nj-23812:support to redirect to profile from coupon
7978        $this->Session->write('register2',array('user_id' => $user['id']));
7979         $this->Session->write('check-step1',true);
7980         $this->Session->write('check-step2',true);
7981        $this->Session->read('register_user_id',$user['id']);
7982
7983        $this->set('cardLogo', myTools::getWorldpayCardLogo($user['card_brand']));
7984        $this->set('zeusTransactionFlag', true);
7985        $this->set('paymentHash', $pt['payment_hash']);
7986        $this->set('amount', str_replace('.00', '', $freeTrialData['amount']));
7987        $this->set('currencyCode', $user['currency_code']);
7988        $this->set('formType', $formType);
7989        $this->setPaymentViewVars();
7990
7991        // - NJ-18780 : set payment vars
7992        $this->setLitePaymentInfoView($user,true,true);
7993
7994        if ($this->RequestHandler->isMobile()) {
7995            $this->set('isSPView', true);
7996            $this->set('userApiToken', $user['api_token']);
7997        }
7998
7999        $renderParam = array(
8000            'forceMobile' => true,
8001            'this' => $this,
8002            'spView' => '/Mobile/Payment/payment_credit_register',
8003            'layout' => 'mobile'
8004        );
8005
8006        myTools::render($renderParam);
8007    }
8008    
8009    private function checkIfChargedAfterChallenge($userId, $fromAction) {
8010        if (!$userData = $this->sharedUserData['User']) {
8011            return $this->redirect(myTools::getUrl() . '/');
8012        }
8013
8014        if (!class_exists('myMemcached')) {
8015            App::uses('myMemcached', 'Lib');
8016        }
8017
8018        $myMemcachedVar = new myMemcached();
8019
8020        // get zeus challenge flag
8021        $zeus3DSecureChallengeFlg = $myMemcachedVar->get('zeus3DSecureChallengeFlg_' . $userId);
8022
8023        if ($zeus3DSecureChallengeFlg) {
8024            $zeus3DSecurePaymentSuccessFlg = $myMemcachedVar->get('zeus3DSecurePaymentSuccessFlg_' . $userId);
8025            $response = !empty($zeus3DSecurePaymentSuccessFlg) && $zeus3DSecurePaymentSuccessFlg == 'OK' ? 'Success_order' : 'failure_order';
8026            $formType = $myMemcachedVar->get('zeus_3dSecure_challenge_formType_' . $userId);
8027
8028            // clear flag
8029            $myMemcachedVar->delete('zeus3DSecureChallengeFlg_' . $userId);
8030            $myMemcachedVar->delete('zeus_3dSecure_challenge_formType_' . $userId);
8031            $myMemcachedVar->delete('zeus3DSecurePaymentSuccessFlg_' . $userId);
8032        }
8033
8034        if (
8035            (isset($response) && !empty($response)) && 
8036            (
8037                (is_array($response) && is_string($response[0]) && strtolower($response[0]) === "success_order") || 
8038                (is_string($response) && strtolower($response) === "success_order")
8039            )
8040        ) {
8041            // for payment_credit_register checker
8042            if($fromAction == 'register') {
8043                if($this->Session->read('PaymentCreditRegisterInfo')) {
8044                    $this->Session->delete('PaymentCreditRegisterInfo');
8045                }
8046                
8047                if(!class_exists('myMailer')) {
8048                    App::uses('myMailer', 'Lib');
8049                }
8050                $mail_id = Configure::read('site_in_mail.student_registration_complete');
8051                if ($userData &&  !in_array($userData['currency_code'], Configure::read('global_free_trail_currencies') ) ) {
8052                    $mail_id = Configure::read('site_in_mail.registration_no_trial_currencies');
8053                }
8054                myMailer::sendTemplateMail($mail_id, $userData['email'], $userData, array(), 'User');
8055                //NJ-13482
8056                $this->Session->write('payment_credit_register_complete', true);
8057                return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_register_complete'));
8058
8059            // for payment_credit_charge checker
8060            } elseif($fromAction == 'rejoin') {
8061                if($this->Session->read('PaymentCreditChargeInfo')) {
8062                    $this->Session->delete('PaymentCreditChargeInfo');
8063                }
8064
8065                $action = 'payment_credit_charge_complete';
8066                // if complimentary plan user before
8067                if ($this->memcache->get('com_plan_user_'.$userData['id'])) {
8068                    $this->memcache->delete('com_plan_user_'.$userData['id']);
8069                    $action = 'coupon_payment_credit_charge_complete';
8070                }
8071
8072                // Teacher Perks : Student re-enroll
8073                if ( $formType == Configure::read('payment_credit_force_charge')) {
8074                    ClassRegistry::init('TeacherPerksAccount')->reEnroll(['user_id' => $userData['id']]);
8075                }
8076                
8077                //    NC-7644 Add code reward for re-enroolling with the campaign code
8078                $this->log(__METHOD__ ."sai_debug -> Add 500 Coin Reward for re-enroll: ", "error");
8079                $this->addCoinRewardForReenroll($userData);
8080
8081                // - add monthly mc coin if lite plan user 
8082                if ($formType == Configure::read('payment_lite_credit_paid')) {
8083                    $this->liteUserAddCoinRewardForReenroll(array('id' => $userData['id']));
8084                }
8085                
8086                return $this->redirect(array('controller' => 'payment', 'action' => $action));
8087
8088            // for payment_credit_retry checker
8089            } elseif($fromAction == 'retry') {
8090                if($formType == Configure::read('payment_credit_retry')) {
8091                    if($this->Session->read('PaymentCreditRetryInfo')) {
8092                        $this->Session->delete('PaymentCreditRetryInfo');
8093                    }
8094
8095                    if($this->Session->read('PaymentCreditRetryInfoCorporateAmount')) {
8096                        $this->Session->delete('PaymentCreditRetryInfoCorporateAmount');
8097                    }
8098
8099                    // - flag manual paying user success
8100                    UserTable::saveManualPayingUsersToMemcache($userData['id']);
8101                    return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_retry_complete'));
8102                }
8103
8104            // for payment_credit_change checker
8105            } elseif($fromAction == 'payment_change') {
8106                $requestData = $this->request->query;
8107
8108                if(isset($requestData) && !empty($requestData)) {
8109                    if ( isset($requestData['page_origin']) ) {
8110                        if ( isset($requestData['page_origin']) && $requestData['page_origin'] == 1 ) { // Store
8111                            $url = "page_origin=".$requestData['page_origin'];
8112                        } elseif (isset($requestData['page_origin']) && $requestData['page_origin'] == 2) { // Ebook
8113                            $url = "page_origin=".$requestData['page_origin'];
8114                        }
8115                    }
8116                }
8117
8118                if (isset($url) && !empty($url)) {
8119                    return $this->redirect(array('controller' => 'store', 'action' => 'card_register_complete','?' => $url));
8120                } else{
8121                    return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_change_complete'));
8122                }
8123            }
8124        }
8125    }
8126
8127    private function wp_credit_register() {
8128        // set variables
8129        $user = $this->sharedUserData['User'];
8130        $apiToken = $user['api_token'];
8131        $memKey = "pc_wp_register_card_type_{$apiToken}";
8132        $memData = $this->memcache->get($memKey);
8133        $cardType = isset($memData['cardType']) ? $memData['cardType'] : 0;
8134
8135        // get free trial plan payment data
8136        $freeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
8137            'currencyCode' => $user['currency_code'],
8138            'paymentPlanId' => Configure::read('payment_plans.free_trial'),
8139            'logFileName' => 'card_reregister'
8140        ));
8141
8142
8143        // - NJ-23812
8144        if ($this->Session->read('credit_skip_to_confirmation')) {
8145            $this->Session->delete('credit_skip_to_confirmation');
8146        }
8147
8148
8149        // - NJ-23812:  add session to allow to profile page and coupon
8150        if (isset($user['User'])){
8151            $this->Session->write('register2',array('user_id' => $user['User']['id']));
8152            $this->Session->read('register_user_id',$user['User']['id']);
8153        }
8154         $this->Session->write('check-step1',true);
8155         $this->Session->write('check-step2',true);
8156
8157        $isCardRegistered = false;
8158        if (    
8159            (!empty($user['card_brand']) && !empty($user['card_number'])) 
8160        ) {
8161            $isCardRegistered = true;
8162        }
8163
8164        // redirect to mypage if free trial plan payment is not supported
8165        if (!$freeTrialData) {
8166            return $this->redirect('/');
8167        }
8168
8169        if ($this->request->is('post')) {
8170            $cardType = $this->request->data['cardType'];
8171
8172            // memcache card type value
8173            $this->memcacheCardType(array(
8174                'key' => $memKey,
8175                'value' => array('cardType' => $cardType)
8176            ));
8177
8178            // redirect to hosted page if using new card ($cardType = 1)
8179            if ($cardType) {
8180                return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/payment/wp_credit_register_form");
8181            // redirect to confirm page if using existing card ($cardType = 0)
8182            } else {
8183
8184                // - NJ-23812: write session to skip and auto charge 
8185                $this->Session->write('credit_skip_to_confirmation',true);
8186
8187
8188                return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/payment/payment_credit_register_confirm");
8189            }
8190        }
8191
8192        /* check if there is error during payment process */
8193        if ($errorType = isset($this->request->query['wpErrType']) ? $this->request->query['wpErrType'] : null) {
8194            if ($error = myTools::getWorldpayErrorMsg($errorType)) {
8195                $this->set('error', $error);
8196            }
8197        } else {
8198            $memErrorKey = 'pc_wp_register_error_'. $apiToken;
8199            if ($error = $this->memcache->get($memErrorKey)) {
8200                $this->set('error', $error);
8201
8202                // delete memcache error
8203                $this->memcache->delete($memErrorKey);
8204            }
8205        }
8206
8207        // //if no registered card, redirect to hosted page if using new card ($cardType = 1)
8208        // if (!$isCardRegistered) {
8209        //     // memcache card type value
8210        //     $this->memcacheCardType(array(
8211        //         'key' => $memKey,
8212        //         'value' => array('cardType' => 1)
8213        //     ));
8214        //     return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/payment/wp_credit_register_form");
8215        // }
8216
8217        if (!$isCardRegistered) {
8218            $cardType = 1;
8219        }
8220
8221
8222        // - NJ-23812 
8223        $formType = Configure::read('payment_credit_authentication');
8224        $_user = new UserTable($this->sharedUserData['User']);
8225
8226        // check if allowed aftee
8227        $this->checkAfteeSupported($this->sharedUserData['User'],true);
8228
8229        if ($this->RequestHandler->isMobile()) {
8230
8231            //NJ-3882 Require SMS Authentication before Credit Card Registration
8232            $this->PhoneVerifyCheckLog->openDBReplica();
8233            $countTotalVerify = $this->PhoneVerifyCheckLog->find('count',array(
8234                'conditions'=> array(
8235                    'user_id' => $this->Auth->user('id'),
8236                    'status' => 0
8237                )
8238            ));
8239            $this->PhoneVerifyCheckLog->closeDBReplica();
8240            $this->set('countTotalVerify',$countTotalVerify);
8241
8242            $this->set('user',new UserTable($this->sharedUserData['User']));
8243
8244        }else{
8245            $this->set('user', $_user);
8246        }
8247
8248        // - set view vars
8249        $this->set('pmtValue', 'auth');
8250        $this->set('apiToken', $apiToken);
8251        $this->set('logFileName', 'card_reregister');
8252        $this->set('nc_terminal_type', 1); // pc
8253        $this->set('memKeyError', 'pc_wp_register_error_' . $apiToken);
8254        $this->set('formType', $formType);
8255        $this->set('referrer', urlencode(myTools::getUrl() . "/{$this->localizeDir}/payment/payment_credit_register"));
8256        $this->set('successUrl', urlencode(myTools::getUrl() . "/{$this->localizeDir}/payment/payment_credit_register_complete"));
8257        $this->set('isCardRegistered',$isCardRegistered);
8258        // // - end NJ-23812
8259        
8260
8261        // - NJ-23812: display premium data 
8262        $currencyCode = $user['currency_code'];
8263        $premiumData = $this->PaymentPlanPrice->getPaymentData(array(
8264            'currencyCode' => $currencyCode,
8265            'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
8266            'logFileName' => 'card_reregister'
8267        ));
8268
8269        $currencyData = $this->Currency->getSymbolAndPosition($currencyCode);
8270
8271        $this->set('monthlyPrice', myTools::formatAmount($premiumData['amount']));
8272        $this->set('monthylyPriceNoTax', myTools::formatAmount($premiumData['amountConstTaxDeducted']));
8273        $this->set('monthlyPriceSymbol',myTools::getCurrencySymbol($currencyCode));
8274
8275        // set view variables
8276        $this->set('cardLogo', myTools::getWorldpayCardLogo($user['card_brand']));
8277        $this->set('cardType', $cardType);
8278        $this->set('cardBrand', $user['card_brand']);
8279        $this->set('cardNumber', $user['card_number']);
8280        $this->render('/Payment/wp_payment_credit_register');
8281
8282        $renderParam = array(
8283            'forceMobile' => true,
8284            'this' => $this,
8285            'spView' => '/Mobile/Payment/wp_payment_credit_register',
8286            'layout' => 'mobile'
8287        );
8288
8289        myTools::render($renderParam);
8290    }
8291    /**
8292     * @api {get} /:language/payment/payment_credit_register_confirm payment_credit_register_confirm()
8293     * @apiName payment_credit_register_confirm
8294     * @apiGroup Payment
8295     * @apiDescription This function is used to display the credit card registration confirmation page.
8296     * 
8297     * @apiParam {String} language Language code of the user
8298     * 
8299     * @apiSuccess {View} Render Displays the credit card registration confirmation page.
8300     * @apiSuccess {View} Redirect Redirects to zeus credit register confirm function if currency is equals to jpy.
8301     * @apiSuccess {View} Redirect Redirects towp credit register confirm function if currency is not equals to jpy.
8302     * 
8303     * @apiSuccessExample Success Response:
8304     * Displays the credit card registration confirmation page.
8305     * 
8306     * @apiSuccessExample Success Response Redirect to zeus process if currency is equals to jpy:
8307     * Redirects to zeus_credit_register_confirm function if currency is equals to jpy.
8308     * 
8309     * @apiSuccessExample Success Response Redirect to wp process if currency is not equals to jpy:
8310     * Redirects to wp_credit_register_confirm function if currency is not equals to jpy.
8311     * 
8312     * @apiSampleRequest off
8313     */
8314    public function payment_credit_register_confirm() {
8315        $this->checkUser(Configure::read('payment_credit_authentication'));
8316
8317        // redirect to zeus process if currency is equals to jpy
8318        if ($this->sharedUserData['User']['currency_code'] == Configure::read('default.user_currency')) {
8319            $this->zeus_credit_register_confirm();
8320        // redirect to wp
8321        } else {
8322            $this->wp_credit_register_confirm();
8323        }
8324    }
8325
8326    private function zeus_credit_register_confirm() {
8327        $data = $this->Session->read('PaymentCreditRegisterInfo');
8328        if (!$data) {
8329            return $this->redirect(myTools::getUrl() . '/');
8330        }
8331
8332        $readSkipConfirmation = $this->Session->read('credit_skip_to_confirmation');
8333        if ($readSkipConfirmation){
8334            $this->Session->delete('credit_skip_to_confirmation');
8335        }
8336        $readSkipConfirmation = true;//force to skip confirmation page
8337
8338        if ($this->request->is('post') || $readSkipConfirmation) {
8339            # check if token matches token in session
8340            $checkToken = $this->checkToken($data['token']);
8341            # check if token is true
8342            if ($checkToken) {
8343                # unset previously set tokens
8344                $this->unsetToken();
8345                $formType = Configure::read('payment_credit_authentication');
8346                $referrer = array('controller' => 'Payment', 'action' => 'payment_credit_register');
8347                $this->z_start($data, $formType, $referrer);
8348            }
8349
8350        }
8351
8352        if (isset($data['ZPaymentFullLogs']['cardnumber']) && !empty($data['ZPaymentFullLogs']['cardnumber'])) {
8353            $this->set('cardNumber', end(str_split($data['ZPaymentFullLogs']['cardnumber'], 4)));
8354        } else {
8355            $this->getAndSetCardInfo($this->sharedUserData['User']);
8356        }
8357
8358        $this->set('data', $data);
8359
8360        $renderParam = array(
8361            'forceMobile' => true,
8362            'this' => $this,
8363            'spView' => '/Mobile/Payment/payment_credit_register_confirm',
8364            'layout' => 'mobile'
8365        );
8366
8367        myTools::render($renderParam);
8368    }
8369
8370    private function wp_credit_register_confirm() {
8371        $this->response->disableCache();
8372        // set variables
8373        $logFileName = 'card_reregister';
8374        $user = $this->sharedUserData['User'];
8375        $currencyCode = $user['currency_code'];
8376        $userId = $user['id'];
8377        $apiToken = $user['api_token'];
8378
8379        $readSkipConfirmation = $this->Session->read('credit_skip_to_confirmation');
8380        if ($readSkipConfirmation) {
8381            $this->Session->delete('credit_skip_to_confirmation');
8382        }
8383
8384        $memKey = "pc_wp_register_card_type_{$apiToken}";
8385        // redirect to mypage if memcache card type is not set
8386        if (!$this->memcache->get($memKey)) {
8387            return $this->redirect('/');
8388        }
8389
8390        if ($this->request->is('post') || $readSkipConfirmation) {
8391            $paymentMethodType = myTools::getWPPaymentMethodType($user['card_brand'], 'auth');
8392            $merchantCode = myTools::getWPMerchantCode($paymentMethodType);
8393            $paymentMethod = explode('_', $paymentMethodType);
8394            $paymentMethod = isset($paymentMethod[0]) ? $paymentMethod[0] : null;
8395            $orderCode = myTools::generateOrderCode($userId);
8396            $currencyExponents = Configure::read('worldpay.currency_exponents');
8397            $exponent = $currencyExponents[$currencyCode];
8398            $nominalAmountArr = myTools::getWorldpayNominalAmountList($paymentMethod, $merchantCode);
8399
8400            // get nominal amount with checking currency exponent
8401            $totalAmountArr = myTools::wpGetAmount($exponent, $nominalAmountArr[$currencyCode]);
8402            $ncAmount = $totalAmountArr['ncAmount'];
8403            $wpAmount = $totalAmountArr['wpAmount'];
8404
8405            // get free trial payment data
8406            $freeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
8407                'currencyCode' => $currencyCode,
8408                'paymentPlanId' => Configure::read('payment_plans.free_trial'),
8409                'logFileName' => $logFileName
8410            ));
8411
8412            // redirect to mypage if free trial plan payment is not supported
8413            if (!$freeTrialData) {
8414                return $this->redirect('/');
8415            }
8416
8417            $user['payment_plan_id'] = $freeTrialData['paymentPlanId'];
8418            $user['price_id'] = $freeTrialData['priceId'];
8419
8420            $wpData = array(
8421                'cardToken' => $user['card_token'],
8422                'merchantCode' => $merchantCode,
8423                'paymentHash' => $orderCode,
8424                'wpPaymentAmount' => $wpAmount
8425            );
8426
8427            // set payment amount
8428            $user['paymentAmount'] = 0;
8429            $formType = Configure::read('payment_credit_authentication');
8430
8431            // create payment transaction
8432            if (!$pt = $this->createPaymentTransaction($formType, $user, $wpData)) {
8433                $this->log(__METHOD__ .' Failed to save payment transaction. Params --> ' . json_encode($wpData), $logFileName);
8434                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to save payment transaction. Params --> ' . json_encode($wpData), 'error');
8435                return $this->redirect('/');
8436            }
8437
8438            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - After save payment transaction. Params --> ' . json_encode($wpData), 'error');
8439
8440            // if aftee payment
8441            if ($user['card_company'] == Configure::read('card_company.aftee') || ($user['card_brand'] == "AFTEE" && !empty($user['aftee_transaction_identifier']))) {
8442
8443                // default result
8444                $checkRes = array(
8445                    'OrderCode' => $orderCode,
8446                    'authentication_token' => $user['card_token'],
8447                    'response' => 'Aftee payment amount is zero',
8448                    'customer' => array(
8449                        'phone_number' =>  $user['phone_number']
8450                    )
8451                );
8452                $receivableResult = json_encode($checkRes);
8453                $afteeTransactionIdentifier = $user['aftee_transaction_identifier'];
8454
8455
8456                if ($user['paymentAmount'] > 0) {
8457
8458                    if (!class_exists('AfteePaymentService')) {
8459                        App::uses('AfteePaymentService','Lib');
8460                    }
8461                    $afteeService = new AfteePaymentService();
8462                    $afteeChecksumData = array(
8463                        'shopItemId' => "AFTEE" . $formType,
8464                        'itemName' => 'CreditRegisterUsingExistingCard',
8465                        'itemPrice' => $user['paymentAmount'],
8466                        'itemCount' => 1,
8467                        'customerPhoneNumber' => $user['phone_number'],
8468                        'customerEmail' => $user['email'],
8469                        'shopTransactionNo' => $orderCode,
8470                        'userID' =>  $user['id']
8471                    );
8472                    $checksum = $afteeService->generateChecksum($afteeChecksumData, false);
8473                    $afteeData = array(
8474                        'authentication_token' => $user['card_token'],
8475                        'related_id' => $user['aftee_transaction_identifier'],
8476                        'checksum' => $checksum['checksum'],
8477                        'shop_transaction_no' => $orderCode,
8478                        'transaction_options' => array(1)
8479                    );
8480            
8481                    $afteePaymentData = array_merge($afteeData, $checksum['settlementData']);
8482        
8483                    // aftee execute payment
8484                    $receivableResult = $afteeService->directPayment($afteePaymentData);
8485                    $checkRes = json_decode($receivableResult, true);
8486
8487
8488                    if ( isset($checkRes['object']) && $checkRes['object'] == 'transaction') {
8489                        $prPaymentSuccess = true;
8490                    } else if ( !array_key_exists("object", $checkRes) || (isset($checkRes['object']) && $checkRes['object'] == 'error')) {
8491                        $prPaymentSuccess = false;
8492                    }
8493
8494                    $afteeTransactionIdentifier = isset($checkRes['id']) && !empty($checkRes['id']) ? $checkRes['id'] : NULL;
8495                    if (isset($checkRes['related_transaction']) && !empty($checkRes['related_transaction'])) {
8496                        $afteeTransactionIdentifier = $checkRes['related_transaction'];
8497                    }
8498                    $orderCode = isset($checkRes['shop_transaction_no']) && !empty($checkRes['shop_transaction_no']) ? $checkRes['shop_transaction_no'] : NULL;
8499                    $checkRes['OrderCode'] = $orderCode;
8500                }
8501
8502                // process payment data
8503                if ($prPaymentSuccess || $user['paymentAmount'] == 0) {
8504                    // set user model
8505                    $uModel = $this->User;
8506                    $dataSource = $uModel->getDataSource();
8507                    $dataSource->begin();
8508
8509                    $afteeParams = array(
8510                        'data' => $checkRes,
8511                        'ptData' => $pt,
8512                        'logFileName' => $logFileName,
8513                        'dataSource' => $dataSource,
8514                        'amount' => $user['paymentAmount'],
8515                        'userData' => $user,
8516                        'transactionIdentifier' => $afteeTransactionIdentifier,
8517                        'aftee' => 1
8518                    );
8519    
8520                    $this->processAfteePayment($afteeParams);
8521                }
8522
8523                // update payment transaction
8524                $updateData = array(
8525                    'id' => $pt['id'],
8526                    'fields' => array(
8527                        'status' => $prPaymentSuccess,
8528                        'response_text' => array('aftee_directPayment_response' => $receivableResult))
8529                );
8530
8531                // update payment transaction
8532                $this->PaymentTransaction->updateAfteePaymentTransaction($updateData);
8533
8534
8535                // redirect to payment_credit_charge with error display if direct payment response is not authorised
8536                if (!$prPaymentSuccess && $user['paymentAmount'] > 0) {
8537                    if (!class_exists('myMemcached')) {
8538                        App::uses('myMemcached', 'Lib');
8539                    }
8540                    $memKeyError = 'pc_wp_register_error_' . $apiToken;
8541                    $memerror = __('トランザクションを完了できません。 もう一度お試しください。');
8542                    $memcached = new myMemcached();
8543                    $memcached->set(array(
8544                        'key' => $memKeyError,
8545                        'value' => $memerror,
8546                        'expire' => 3600 // 1 hour
8547                    ));
8548                    return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/payment/payment_credit_register");
8549                }
8550
8551            } else {
8552
8553                $wpData = array(
8554                    'merchantCode' => $merchantCode,
8555                    'orderCode' => $orderCode,
8556                    'description' => 'Credit Register Using Existing Card',
8557                    'currencyCode' => $currencyCode,
8558                    'exponent' => $exponent,
8559                    'amount' => $wpAmount,
8560                    'cardToken' => $user['card_token'],
8561                    'email' => $user['email'],
8562                    'authenticatedShopperId' => $userId,
8563                    'xmlName' => 'direct_payment_with_token',
8564                    'shopperIpAddress' => $_SERVER["REMOTE_ADDR"],
8565                    'wpTransactionIdentifier' => $user['wp_transaction_identifier'],
8566                    'paymentMethod' => $paymentMethod
8567                );
8568
8569                $result = wpPaymentService::directPayment($wpData);
8570
8571                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - directPayment result --> ' . json_encode($result), 'error');
8572
8573                $updateData = array(
8574                    'id' => $pt['id'],
8575                    'fields' => array('response_text' => array('directPayment_response' => $result)),
8576                    'logFileName' => $logFileName
8577                );
8578
8579                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - before updatePaymentTransaction result --> ' . json_encode($updateData), 'error');
8580
8581                // redirect to retry page if failed to update payment transaction
8582                if (!$this->updatePaymentTransaction($updateData)) {
8583                    return $this->redirect('/');
8584                }
8585
8586                // redirect to wp_credit_register with error display if direct payment response is not authorised
8587                if (!myTools::checkIfWPPaymentResponseIsAuthorised($result)) {
8588                    $params = array(
8589                        'apiToken' => $apiToken,
8590                        'wpResponse' => $result,
8591                        'memKey' => 'pc_wp_register_error_' . $apiToken
8592                    );
8593                    myTools::parseAndSetWPErrorResponse($params);
8594                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - WP Payment not authorised --> ' . json_encode($params), 'error');
8595                    return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/payment/payment_credit_register");
8596                }
8597
8598            }
8599
8600
8601
8602
8603            // delete memcache
8604            if ($this->memcache->get($memKey)) {
8605                $this->memcache->delete($memKey);
8606            }
8607            
8608            // send registration completion email
8609            App::uses('myMailer','Lib');
8610            $mail_id = Configure::read('site_in_mail.student_registration_complete');
8611            if ($user &&  !in_array($user['currency_code'], Configure::read('global_free_trail_currencies') ) ) {
8612                $mail_id = Configure::read('site_in_mail.registration_no_trial_currencies');
8613            }
8614            myMailer::sendTemplateMail($mail_id, $user['email'], $user, array(), 'User');
8615            //NJ-13482
8616            $this->Session->write('payment_credit_register_complete', true);
8617            return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/payment/payment_credit_register_complete");
8618        }
8619
8620        $currencyData = $this->Currency->getSymbolAndPosition($currencyCode);
8621        $this->set('freeTrialPrice', myTools::addPriceSymbol(0, $currencyData['symbol'], $currencyData['prefix_suffix_flg']));
8622
8623        // set view variables
8624        $this->set('cardLogo', myTools::getWorldpayCardLogo($user['card_brand']));
8625        $this->set('cardBrand', $user['card_brand']);
8626        $this->set('cardNumber', $user['card_number']);
8627        $this->set('cardCompany', $user['card_company']);
8628        $this->render('/Payment/wp_payment_credit_register_confirm');
8629
8630        $renderParam = array(
8631            'forceMobile' => true,
8632            'this' => $this,
8633            'spView' => '/Mobile/Payment/wp_payment_credit_register_confirm',
8634            'layout' => 'mobile'
8635        );
8636
8637        myTools::render($renderParam);
8638    }
8639    /**
8640     * @api {get} /:language/payment/paypal_payment_credit_register_confirm paypal_payment_credit_register_confirm()
8641     * @apiName paypal_payment_credit_register_confirm
8642     * @apiGroup Payment
8643     * @apiDescription This function is used to display the credit card registration confirmation page using paypal.
8644     * 
8645     * @apiParam {String} language Language code of the user
8646     * 
8647     * @apiSuccess {View} Render Displays the credit card registration confirmation page using paypal.
8648     * @apiSuccess {View} Render Displays the credit card registration confirmation page using paypal sp version for mobile.
8649     * 
8650     * @apiError {View} Redirect Redirects to {{ENV}}/ missing paypal payment credit register data.
8651     * 
8652     * @apiSuccessExample Success Response PC:
8653     * Displays the credit card registration confirmation page using paypal.
8654     * 
8655     * @apiSuccessExample Success Response Mobile:
8656     * Displays the credit card registration confirmation page using paypal sp version for mobile.
8657     * 
8658     * @apiErrorExample Error Response:
8659     * Redirects to {{ENV}}/
8660     * 
8661     * @apiSampleRequest off
8662     */
8663    public function paypal_payment_credit_register_confirm() {
8664        $this->checkUser(Configure::read('payment_credit_authentication'));
8665
8666        $data = $this->Session->read('paypalPaymentCreditRegisterData');
8667        if (!$data) {
8668            $this->log(__METHOD__ . ' Missing paypal payment credit register data. --> ' . json_encode($data) . ' | user id  --> ' . json_encode($this->sharedUserData['User']['id']), 'card_reregister');
8669            return $this->redirect(myTools::getUrl());
8670        }
8671
8672        // set payment gateway type
8673        $this->memcache->set(array(
8674            'key' => 'creditReregisterPaymentGatewayType_' . $this->sharedUserData['User']['api_token'],
8675            'value' => $data['payment_gateway_type'],
8676            'expire' => 3600 // 1 hour
8677        ));
8678
8679        $this->set('userApiToken', $this->sharedUserData['User']['api_token']);
8680        $this->set('isSPView', true);
8681        $this->set('paypalFlg', true); // use for modal loader
8682        $renderParam = array(
8683            'forceMobile' => true,
8684            'this' => $this,
8685            'spView' => '/Mobile/Payment/paypal_payment_credit_register_confirm',
8686            'layout' => 'mobile'
8687        );
8688
8689        myTools::render($renderParam);
8690    }
8691    /**
8692     * @api {get} /:language/payment/paypal_payment_credit_register_process/:token/:negativeTesting paypal_payment_credit_register_process()
8693     * @apiName paypal_payment_credit_register_process
8694     * @apiGroup Payment
8695     * @apiDescription This function is used to process the credit card registration using paypal.
8696     * 
8697     * @apiParam {String} language Language code of the user
8698     * @apiParam {String} token User's API token
8699     * @apiParam {Number} negativeTesting Negative testing flag 1 for true, 0 for false
8700     * 
8701     * @apiSuccess {View} Redirect Redirects to {{ENV}}/:language/payment/payment_credit_register_compelete page if successful.
8702     * 
8703     * @apiError {View} Redirect Redirects to {{ENV}}/ page if token is not set or does not match the user's API token.
8704     * @apiError {View} Redirect Redirects to {{ENV}}/payment/payment_credit_register page if negative testing is enabled
8705     * @apiError {View} Redirect Redirects to {{ENV}}/ page if session payment credit register data is missing.
8706     * @apiError {View} Redirect Redirects to {{ENV}}/payment/payment_credit_register page if settlement fails.
8707     * 
8708     * @apiSuccessExample Success Response:
8709     * Redirects to {{ENV}}/:language/payment/payment_credit_register_compelete
8710     * 
8711     * @apiErrorExample Error Response token not set:
8712     * Redirects to {{ENV}}/
8713     * 
8714     * @apiErrorExample Error Response Negative Testing:
8715     * Redirects to {{ENV}}/payment/payment_credit_register
8716     * 
8717     * @apiErrorExample Error Response Missing Data:
8718     * Redirects to {{ENV}}/
8719     * 
8720     * @apiErrorExample Error Response Settlement Fails:
8721     * Redirects to {{ENV}}/payment/payment_credit_register
8722     * 
8723     * @apiSampleRequest off
8724     */
8725    public function paypal_payment_credit_register_process() {
8726        $this->autoRender = false;
8727        $this->layout = false;
8728
8729        $logFileName = 'paypal_debug';
8730        $user = $this->sharedUserData['User'];
8731        $userId = $user['id'];
8732        $get = $this->request->query;
8733
8734        //- NJ-27262 clear from landing page
8735        $this->Cookie->delete('chocotto_lp');
8736
8737        // negative testing
8738        if (isset($get['negativeTesting']) && $get['negativeTesting']) {
8739            $this->Session->setFlash('決済失敗', array("element" => "flashfail"));
8740
8741            $memKey = 'paypalBillingAgreementData_' . $get['token'];
8742
8743            // delete memcache billing agreement data
8744            if ($this->memcache->get($memKey)) {
8745                $this->memcache->delete($memKey);
8746            }
8747
8748            return $this->redirect(myTools::getUrl('payment/payment_credit_register'));
8749        }
8750
8751
8752        // get session payment credit register data
8753        $data = $this->Session->read('paypalPaymentCreditRegisterData');
8754
8755        // redirect to top page if empty
8756        if (!$data) {
8757            $this->log(__METHOD__ . ' Missing paypal payment credit register data. --> ' . json_encode($data) . ' | user id  --> ' . json_encode($userId), $logFileName);
8758            return $this->redirect(myTools::getUrl());
8759        }
8760
8761        // redirect to top page if get token is not set or get token is not same as user api token
8762        if (!isset($get['token']) || (isset($get['token']) && $get['token'] != $user['api_token'])) {
8763            $this->log(__METHOD__ . ' Token does not exist. --> ' . json_encode($get) . ' | user data  --> ' . json_encode($user), $logFileName);
8764            return $this->redirect(myTools::getUrl());
8765        }
8766
8767        $data['formType'] = Configure::read('payment_credit_authentication');
8768
8769        $userTable = new UserTable($user);
8770        $membershipTypes = UserTable::getEngMembershipTypeData();
8771        $membershipTypeIndex = $userTable->getMembershipTypeIndex();
8772
8773        $paymentPlanType = (isset($get['payment_plan_type']) && $get['payment_plan_type'] ) ? $get['payment_plan_type'] : 0;
8774
8775        $user['statusBefore'] = $membershipTypes[$membershipTypeIndex];
8776        $user['statusAfter'] = $membershipTypes[2];
8777
8778        // update if select lite plan
8779        if ($paymentPlanType == Configure::read('register_plan_types.light')) {
8780            // - fetch the lite payment plan 
8781            $litefreeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
8782                'currencyCode' => $user['currency_code'],
8783                'paymentPlanId' => Configure::read('payment_plans.light_plan_free'),
8784                'logFileName' => 'card_reregister'
8785            ));
8786
8787            $_lightPlanFreeMem = Configure::read('membership_type_lightplan_free');
8788            $user['statusAfter'] = $membershipTypes[$_lightPlanFreeMem];// update the status after to lite plan free
8789
8790            // - set update data 
8791            $data['paymentPlanData'] = $litefreeTrialData;// set to update the plan use
8792
8793            // update the form type 
8794            $data['formType'] = myTools::getLitePlanUserFormType(Configure::read('payment_plans.light_plan_free'));
8795
8796        // if annual discount option
8797        } elseif ($paymentPlanType == Configure::read('register_plan_types.premium_with_annual_discount_option')) {
8798            $annualDiscountOptionData = $this->DiscountOptionsPrice->getPaymentData(['currencyCode' => $userTable->currency_code, 'discountOptionId' => Configure::read('discount_option.annual.plan_id')]);
8799    
8800            // redirect to credit page if annual discount option does not exist or is not enabled
8801            if (!$annualDiscountOptionData) {
8802                $this->log(__METHOD__ . ' Annual discount pption does not exist. --> ' . json_encode($get) . ' | data  --> ' . json_encode($data), $logFileName);
8803                return $this->redirect(myTools::getUrl());
8804            }
8805
8806            $annualDiscountOptionData['amount'] = 0; // change amount to 0 since this is a subscription
8807            $annualDiscountOptionData += [
8808                'dosh_event' => Configure::read('discount_option.dosh_event.annual_discount'),
8809                'dosh_status' => Configure::read('discount_option.dosh_status.subscription')
8810            ];
8811
8812            $data['discountOption'] = $annualDiscountOptionData;
8813
8814        //- chocotto payment plan
8815        } elseif ($paymentPlanType == Configure::read('register_plan_types.chocotto')) {
8816            // - fetch the chocotto payment plan 
8817            $chocottofreeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
8818                'currencyCode' => $user['currency_code'],
8819                'paymentPlanId' => Configure::read('payment_plans.free_trial_chocotto'),
8820                'logFileName' => 'card_register'
8821            ));
8822
8823            $this->UsersDetail->chocottoCampUserDetails($user['id']);
8824            $_chocottoPlanFreeMem = Configure::read('membership_type_chocotto_plan_free');
8825            $user['statusAfter'] = $membershipTypes[$_chocottoPlanFreeMem];// update the status after to lite plan free
8826
8827            // - set update data 
8828            $data['paymentPlanData'] = $chocottofreeTrialData;// set to update the plan use
8829
8830            // update the form type 
8831            $data['formType'] = myTools::getChocottoPlanUserFormType(Configure::read('payment_plans.free_trial_chocotto'));
8832
8833        }
8834
8835        // process paypal settlement
8836        $result = $this->paypalSaveBillingAgreement($data, $user);
8837
8838        // delete session payment credit register data
8839        $this->Session->delete('paypalPaymentCreditRegisterData');
8840
8841        // redirect to reregister page if result is false
8842        if (!$result['success']) {
8843            $this->Session->setFlash('決済失敗', array("element" => "flashfail"));
8844
8845            $memKey = 'paypalBillingAgreementData_' . $get['token'];
8846
8847            // delete memcache billing agreement data
8848            if ($this->memcache->get($memKey)) {
8849                $this->memcache->delete($memKey);
8850            }
8851
8852            $result['status'] = 0;
8853
8854            // update payment transaction
8855            $this->PaymentTransaction->paypalUpdatePaymentTransaction($result);
8856
8857            return $this->redirect(myTools::getUrl('payment/payment_credit_register'));
8858        }
8859
8860        $reCampaign = $this->UserWithdrawReenrollCampaign->find('first', array(
8861            'fields' => array('id', 'status'),
8862            'conditions' => array('user_id' => $userId)
8863        ));
8864
8865        if (
8866            isset($reCampaign['UserWithdrawReenrollCampaign']['status']) &&
8867            $reCampaign['UserWithdrawReenrollCampaign']['status'] == 0 &&
8868            $user['currency_code'] == Configure::read('currency_jpy') &&
8869            $paymentPlanType != Configure::read('register_plan_types.chocotto') //- no service coin for chocotto plan
8870        ) {
8871            $uwrcId = $reCampaign['UserWithdrawReenrollCampaign']['id'];
8872
8873            // give 500 points
8874            $pointParams = array(
8875                'userId' => $userId,
8876                'point' => 500, // re-register campaign points
8877                'kbn' => Configure::read("point_history.bonus"),
8878                'kbnType' => 1, // add coin
8879                'coinType' => 2, // service coin
8880                'coinFailMessage' => Configure::read('coin.failed.buy_coin')
8881            );
8882
8883            ClassRegistry::init('UsersPoint')->performPointTransaction($pointParams);
8884
8885            // update re-enroll campaign status
8886            $rcData = array('id' => $uwrcId, 'status' => 1);
8887
8888            $this->UserWithdrawReenrollCampaign->clear();
8889            $this->UserWithdrawReenrollCampaign->read(array_keys($rcData), $uwrcId);
8890            $this->UserWithdrawReenrollCampaign->set($rcData);
8891            $this->UserWithdrawReenrollCampaign->save();
8892        }
8893
8894        // send registration completion email
8895        App::uses('myMailer','Lib');
8896        $mailId = Configure::read('site_in_mail.student_registration_complete');
8897        myMailer::sendTemplateMail($mailId, $user['email'], $user, array(), 'User');
8898
8899        $memKey = 'creditReregisterPaymentGatewayType_' . $user['api_token'];
8900        // delete memcache payment gateway type
8901        if ($this->memcache->get($memKey)) {
8902            $this->memcache->delete($memKey);
8903        }
8904        // NJ-13482
8905        $this->Session->write('payment_credit_register_complete', true);
8906
8907        return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_register_complete'));
8908    }
8909
8910    /**
8911     * @api {get} /payment/sp_paypal_payment_credit_register_process/:token/:negativeTesting/:payment_plan_type sp_paypal_payment_credit_register_process()
8912     * @apiName sp_paypal_payment_credit_register_process
8913     * @apiGroup Payment
8914     * @apiDescription This endpoint is used to process the credit card registration using paypal for sp mobile.
8915     * 
8916     * @apiParam {String} token User's API token
8917     * @apiParam {Number} negativeTesting Negative testing flag 1 for true, 0 for false
8918     * @apiParam {Number} payment_plan_type Payment plan type
8919     * 
8920     * @apiSuccess {View} Redirect Redirects to {{ENV}}/payment/paypal_payment_credit_register_process page if successful.
8921     * 
8922     * @apiError {View} Redirect Redirects to {{ENV}}/ page if token is not set or does not match the user's API token.
8923     *
8924     * @apiSuccessExample Success Response:
8925     * Redirects to {{ENV}}/payment/paypal_payment_credit_register_process
8926     * 
8927     * @apiErrorExample Error Response:
8928     * Redirects to {{ENV}}/
8929     * 
8930     * @apiSampleRequest off
8931     */
8932    public function sp_paypal_payment_credit_register_process() {
8933        $this->autoLayout = false;
8934        $this->autoRender = false;
8935
8936        $this->checkUser(Configure::read('payment_credit_authentication'));
8937
8938
8939        $params = array();
8940        $get = $this->request->query;
8941        $user = $this->sharedUserData['User'];
8942        $logFileName = 'card_reregister';
8943
8944        $paymentPlanType = (isset($get['payment_plan_type'])) ? $get['payment_plan_type'] : null;
8945
8946        $freeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
8947            'currencyCode' => $user['currency_code'],
8948            'paymentPlanId' => Configure::read('payment_plans.free_trial'),
8949            'logFileName' => $logFileName
8950        ));
8951
8952        if ((int) $paymentPlanType == 1) {
8953            $freeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
8954                'currencyCode' => $user['currency_code'],
8955                'paymentPlanId' => Configure::read('payment_plans.light_plan_free'),
8956                'logFileName' => $logFileName
8957            ));
8958
8959        //- NJ-27262 new chocotto plan
8960        } elseif ($paymentPlanType == Configure::read('register_plan_types.chocotto')) {
8961            $freeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
8962                'currencyCode' => $user['currency_code'],
8963                'paymentPlanId' => Configure::read('payment_plans.free_trial_chocotto'),
8964                'logFileName' => $logFileName
8965            ));
8966        }
8967
8968        if (!$freeTrialData) {
8969            return $this->redirect('/');
8970        }
8971        if (isset($get['token']) && $get['token']) {
8972            $params['token'] = $get['token'];
8973        }
8974        
8975        if (isset($get['negativeTesting']) && $get['negativeTesting']) {
8976            $params['token'] = $get['negativeTesting'];
8977        }
8978        
8979
8980
8981        $data['paymentPlanData'] = $freeTrialData;
8982        $this->Session->write('paypalPaymentCreditRegisterData', $data);
8983        return $this->redirect(array('controller' => 'Payment', 'action' => 'paypal_payment_credit_register_process', '?' => $params));
8984    }
8985
8986    /**
8987     * @api {get} /:language/payment/wp_credit_register_form wp_credit_register_form()
8988     * @apiName wp_credit_register_form
8989     * @apiGroup Payment
8990     * @apiDescription This endpoint is used to display the credit card registration form.
8991     * 
8992     * @apiParam {String} language Language code of the user
8993     *
8994     * @apiSuccess {View} Render Displays the credit card registration form.
8995     * 
8996     * @apiError {View} Redirect Redirects to {{ENV}}/ page if memcache card type is not set.
8997     *  
8998     * @apiSuccessExample Success Response:
8999     * Display the credit card registration form.
9000     * 
9001     * @apiErrorExample Error Response:
9002     * Redirects to {{ENV}}/
9003     * 
9004     * @apiSampleRequest off
9005     */
9006    public function wp_credit_register_form() {
9007        $this->blockWithdrawnSapuriToS();
9008        $this->disablePageForSapuri();
9009        $this->response->disableCache();
9010        $formType = Configure::read('payment_credit_authentication');
9011        $this->checkUser($formType);
9012        $apiToken = $this->sharedUserData['User']['api_token'];
9013
9014        $memKey = "pc_wp_register_card_type_{$apiToken}";
9015        // redirect to mypage if memcache card type is not set
9016        if (!$this->memcache->get($memKey)) {
9017            return $this->redirect('/');
9018        }
9019
9020        //NJ-3882 Require SMS Authentication before Credit Card Registration
9021        $this->PhoneVerifyCheckLog->openDBReplica();
9022        $countTotalVerify = $this->PhoneVerifyCheckLog->find('count',array(
9023            'conditions'=> array(
9024                'user_id' => $this->Auth->user('id'),
9025                'status' => 0
9026            )
9027        ));
9028        $this->PhoneVerifyCheckLog->closeDBReplica();
9029        
9030        $this->CountryCode->openDBReplica();
9031        $countryCodes = $this->CountryCode->find('all',array(
9032            'fields' => array(
9033                'code',
9034                'country_name'
9035            ),
9036            'order' => 'country_name ASC'
9037        ));
9038        $this->CountryCode->closeDBReplica();
9039        $this->set('countryCodes',$countryCodes);
9040        
9041        $user = new UserTable($this->sharedUserData['User']);
9042        $this->set('user', $user);
9043        $this->set('countTotalVerify',$countTotalVerify);
9044
9045        // set view vars
9046        $this->set('pmtValue', 'auth');
9047        $this->set('apiToken', $apiToken);
9048        $this->set('logFileName', 'card_reregister');
9049        $this->set('nc_terminal_type', 1); // pc
9050        $this->set('memKeyError', 'pc_wp_register_error_' . $apiToken);
9051        $this->set('formType', $formType);
9052        $this->set('referrer', urlencode(myTools::getUrl() . "/{$this->localizeDir}/payment/payment_credit_register"));
9053        $this->set('successUrl', urlencode(myTools::getUrl() . "/{$this->localizeDir}/payment/payment_credit_register_complete"));
9054
9055        $renderParam = array(
9056            'forceMobile' => true,
9057            'this' => $this,
9058            'spView' => '/Mobile/Payment/wp_payment_credit_register_form',
9059            'layout' => 'mobile'
9060        );
9061
9062        myTools::render($renderParam);
9063    }
9064
9065    /**
9066     * @api {get} /:language/payment/payment_credit_change payment_credit_change()
9067     * @apiName payment_credit_change
9068     * @apiGroup Payment
9069     * @apiDescription This endpoint is used to display the credit card information change page.
9070     * 
9071     * @apiParam {String} language Language code of the user
9072     * 
9073     * @apiSuccess {View} Render Displays the credit card information change page.
9074     * 
9075     * @apiSuccessExample Success Response:
9076     * Display the credit card information change page.
9077     * 
9078     * @apiSampleRequest off
9079     */
9080    public function payment_credit_change() {
9081        $this->blockWithdrawnSapuriToS();
9082        $this->disablePageForSapuri();
9083        $this->set('title_for_layout', 'クレジットカード情報変更|オンライン英会話のネイティブキャンプ');
9084        $userData = $this->sharedUserData['User'];
9085        $userObj = new UserTable($userData);
9086
9087        // NJ-68818: check if payment was charged after challenge already
9088        $this->checkIfChargedAfterChallenge($userData['id'], 'payment_change');
9089
9090        if(
9091            (
9092                in_array($userObj->getMembershipTypeIndex(), array(12,13)) && 
9093                !empty($userData['corporate_id'])
9094            ) || 
9095            in_array($userObj->getMembershipTypeIndex(), Configure::read('common_corporate_payment_memberships'))
9096        ) {
9097            return $this->redirect(myTools::getUrl() . '/common_corporate_payment?type=' . Configure::read('payment_url_type.corporate_type.corporate_change_payment_credit') . '&from_page=account');
9098        }
9099        // redirect to zeus if currency is equals to jpy
9100        if ($this->sharedUserData['User']['currency_code'] == Configure::read('default.user_currency')) {
9101            $this->zeus_credit_change();
9102        // redirect to wp
9103        } else {
9104            $this->wp_credit_change();
9105        }
9106
9107        // NJ-30828: set view to display user's paypal email
9108        $this->setPaypalUser($userData);
9109    }
9110
9111    private function zeus_credit_change() {
9112        $user = $this->sharedUserData['User'];
9113        $targetUrl = $url = "";
9114
9115        // app plan user
9116        if ($user['card_company'] == Configure::read('card_company.apple') || $user['card_company'] == Configure::read('card_company.google')) {
9117            $message = "アプリよりご登録の方はカード変更ができません。";
9118            $this->Session->setFlash($message, '', array(), 'plan_list');
9119            return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/plan/plan_list");
9120        }
9121
9122        // free user and not corporate individual user
9123        if (
9124            ($user['charge_flg'] == 0 || $user['fail_flg'] == 1) &&
9125            !in_array($user['payment_plan_id'], myTools::getIndividualPaymentPlanIds())
9126        ) {
9127            $message = "無料会員の方はカード変更ができません。";
9128            $this->Session->setFlash($message, '', array(), 'plan_list');
9129            return $this->redirect(myTools::getUrl() . '/plan/plan_list', 301);
9130        }
9131
9132        // get request data
9133        $requestData = $this->request->query;
9134
9135        $telecomDisabled = false;
9136        $formType = Configure::read('payment_credit_change');
9137
9138        // check if disabled is set
9139        if (!isset($requestData["disabled"])) {
9140            # check if allowed
9141            $this->checkUser($formType);
9142        } else {
9143            $telecomDisabled = true;
9144        }
9145
9146        // check if there's a post data
9147        if ($this->request->is('post')) {
9148            $data = $this->request->data;
9149            
9150            // - set zeuspay logs
9151            $data['ZPaymentFullLogs']['clientip'] = Configure::read('ZEUS_clientip');
9152            $data['ZPaymentFullLogs']['telno'] = Configure::read('credit.default_telno');
9153            
9154            // check if token matches token in session
9155            $checkToken = $this->checkToken($data['token']);
9156
9157            // check if token is true
9158            if ($checkToken) {
9159                $this->unsetToken();
9160
9161                if ( isset($requestData['page_origin']) ) {
9162                    if ( isset($requestData['page_origin']) && $requestData['page_origin'] == 1 ) { // Store
9163                        $url = "page_origin=".$requestData['page_origin'];
9164                    } elseif (isset($requestData['page_origin']) && $requestData['page_origin'] == 2) { // Ebook
9165                        $url = "page_origin=".$requestData['page_origin'];
9166                    }
9167                    $data['origin_redirect'] = $url;
9168                }
9169                $referrer =  array('controller' => 'Payment', 'action' => 'payment_credit_change');
9170                $this->z_start($data, $formType, $referrer);
9171            }
9172        }
9173
9174        $user = $this->changePaymentPlanIfTelecomUser($user);
9175        // set payment amount
9176        $user['paymentAmount'] = 0;
9177
9178        // if corporate user
9179        if (isset($user['corporate_id']) && $user['corporate_id']) {
9180            $user['corporateSettlementType'] = Configure::read('corporate_settlement_types.change_card');
9181        }
9182
9183        // - NJ-18780 check if lite plan user 
9184        $isLitePlanUser = in_array($user['payment_plan_id'], Configure::read('lite_payment_plans')) ? true : false;
9185
9186        // set transaction error to 1 if failed to create payment transaction
9187        if (!$pt = $this->createPaymentTransaction(Configure::read('payment_credit_change'), $user)) {
9188            $this->set('transactionError', 1);
9189        }
9190
9191        // NJ-23812 : set view for corporate payment 
9192        $corporateIndiUser = false;
9193        $corporateUser = !empty($user['corporate_id']) && $user['corporate_id'] && isset($user['payment_plan_id']) ? true : false;
9194        $cpData = null;
9195        $cAmount = $cfAmount = "";
9196        $isCardRegistered = (!empty($user['card_brand']) && !empty($user['card_number'])) ? true : false;
9197
9198        $isZeusUser = isset($user['card_company']) && $user['card_company'] == 1 ? true : false;
9199
9200        //NJ-23812: if corporate user
9201        if ($corporateUser) {
9202            // get corporate plan data
9203            $cpData = $this->getCorporatePaymentPlan($user);
9204
9205            // return to top page if not supported
9206            if (!$cpData) {
9207                return $this->redirect(myTools::getUrl() . '/');
9208            }
9209
9210            $cfAmount = $cpData['fAmount'];
9211            $corporateIndiUser = $cpData['corporateIndiUser'];
9212        }
9213        
9214        //NJ-23812: - if corp indie user
9215        if ($corporateIndiUser) {
9216            $corporateTaxRate = Configure::read('tax.increase');
9217            $corpType = myTools::getCoporateTypeUsingPaymentPlanId($user['payment_plan_id']);
9218            // light
9219            if ($corpType == Configure::read('corporate_type.light')) {
9220                $indiCorpTypeLight = true;
9221                $getCorporateData = $this->Corporate->getCorporateLightUserMonthly(array('user_id' => $userId, 'remove_heavy_flg' => true));
9222                $basicFeeWoTax = isset($getCorporateData['basic_fee_discounted']) ? $getCorporateData['basic_fee_discounted'] : 0;
9223        
9224                $cfAmount = myTools::formatAmount($basicFeeWoTax);
9225
9226            // standard or premium
9227            }elseif (in_array($corpType, array(Configure::read('corporate_type.premium'), Configure::read('corporate_type.standard')))) {
9228                $cdrParam = array('corporateId' => $user['corporate_id'], 'corporateType' => $corpType);
9229                $discount = (int)$this->CorporateDiscountRate->getDiscount($cdrParam);
9230                $cAmount = (int)$cpData['amount'] - $discount;
9231                $cfAmount = myTools::formatAmount($cAmount);
9232            }
9233        }
9234
9235        $corpType = myTools::getCoporateTypeUsingPaymentPlanId($user['payment_plan_id']);
9236        // NJ-23812 - set corp user indie
9237        $this->set('corporateIndiUser',$corporateIndiUser);
9238        $this->set('corporateType',$corpType);
9239        $this->set('cpFormatAmount', $cfAmount);
9240        $this->set('cpAmount', $cAmount);
9241        $this->set('isZeusUser', $isZeusUser);
9242
9243        $this->set('cardBrand', $user['card_brand']);
9244        $this->set('cardNumber', $user['card_number']);
9245        $this->set('cardLogo', myTools::getWorldpayCardLogo($user['card_brand']));
9246        
9247        // clear previously set tokens and set new token
9248        $this->unsetToken();
9249        $token = md5(uniqid(rand(), true));
9250        $this->Session->write('Payment.token', $token);
9251
9252        if ( isset($requestData['page_origin']) && $requestData['page_origin'] == 1 ) { // Store
9253            $targetUrl = "?page_origin=1";
9254        } elseif (isset($requestData['page_origin']) && $requestData['page_origin'] == 2) { // Ebook
9255            $targetUrl = "?page_origin=2";
9256        }
9257
9258        // set vars
9259        $this->setSupportPayPal($user);
9260        $this->set('targetUrl', $targetUrl);
9261        $this->set('token', $token);
9262        $this->set("telecomDisabled", $telecomDisabled);
9263        $this->set('zeusTransactionFlag', true);
9264        $this->set('paymentHash', $pt['payment_hash']);
9265        $this->set('userApiToken', $user['api_token']);
9266        $this->setPaymentViewVars();
9267    }
9268    /**
9269     * @api {get} /payment/paypal_payment_credit_change_process/:token paypal_payment_credit_change_process()
9270     * @apiName paypal_payment_credit_change_process
9271     * @apiGroup Payment
9272     * @apiDescription This endpoint is used to process the credit card information change using paypal.
9273     * 
9274     * @apiParam {String} token User's API token
9275     * 
9276     * @apiSuccess {View} Redirect Redirects to {{ENV}}/payment/payment_credit_change_complete page if successful.
9277     * 
9278     * @apiError {View} Redirect Redirects to {{ENV}}/ page if token is not set or does not match the user's API token.
9279     * @apiError {View} Redirect Redirects to {{ENV}}/payment/payment_credit_change page if settlement fails.
9280     * 
9281     * @apiSuccessExample Success Response:
9282     * Redirects to {{ENV}}/payment/payment_credit_change_complete
9283     * 
9284     * @apiErrorExample Error Response token not set:
9285     * Redirects to {{ENV}}/
9286     * 
9287     * @apiErrorExample Error Response Settlement Fails:
9288     * Redirects to {{ENV}}/payment/payment_credit_change
9289     * 
9290     * @apiSampleRequest off
9291     */
9292    public function paypal_payment_credit_change_process() {
9293        $this->autoRender = false;
9294        $this->layout = false;
9295
9296        $logFileName = 'paypal_debug';
9297        $user = $this->sharedUserData['User'];
9298        $userId = $user['id'];
9299        $get = $this->request->query;
9300
9301        // redirect to top page if get token is not set or get token is not same as user api token
9302        if (!isset($get['token']) || (isset($get['token']) && $get['token'] != $user['api_token'])) {
9303            $this->log(__METHOD__ . ' Token does not exist. --> ' . json_encode($get) . ' | user data  --> ' . json_encode($user), $logFileName);
9304            return $this->redirect(myTools::getUrl());
9305        }
9306
9307        $data = array(
9308            'paymentPlanData' => array(
9309                'paymentPlanId' => $user['payment_plan_id'],
9310                'priceId' => $user['price_id']
9311            ),
9312            'formType' => Configure::read('payment_credit_change')
9313        );
9314
9315        // process paypal settlement
9316        $result = $this->paypalSaveBillingAgreement($data, $user);
9317
9318
9319        // redirect to reregister page if result is false
9320        if (!$result['success']) {
9321            $this->Session->setFlash('決済失敗', array("element" => "flashfail"));
9322
9323            $memKey = 'paypalBillingAgreementData_' . $get['token'];
9324
9325            // delete memcache billing agreement data
9326            if ($this->memcache->get($memKey)) {
9327                $this->memcache->delete($memKey);
9328            }
9329
9330            $result['status'] = 0;
9331
9332            // update payment transaction
9333            $this->PaymentTransaction->paypalUpdatePaymentTransaction($result);
9334
9335            return $this->redirect(myTools::getUrl('payment/payment_credit_change'));
9336        }
9337
9338        // redirect to payment change complete
9339        return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_change_complete'));
9340    }
9341
9342    private function wp_credit_change() {
9343
9344        // - NJ-23812
9345        if ($this->Session->read('credit_skip_to_confirmation')) {
9346            $this->Session->delete('credit_skip_to_confirmation');
9347        }
9348
9349        $this->checkUser(Configure::read('payment_credit_change'));
9350        $apiToken = $this->sharedUserData['User']['api_token'];
9351        
9352        /* check if there is error during payment process */
9353        if ($errorType = isset($this->request->query['wpErrType']) ? $this->request->query['wpErrType'] : null) {
9354            if ($error = myTools::getWorldpayErrorMsg($errorType)) {
9355                $this->set('error', $error);
9356            }
9357        } else {
9358            $memErrorKey = 'pc_wp_change_error_'.$apiToken;
9359            if ($error = $this->memcache->get($memErrorKey)) {
9360                $this->set('error', $error);
9361
9362                // delete memcache error
9363                $this->memcache->delete($memErrorKey);
9364            }
9365        }
9366        
9367        // memcache credit change
9368        $this->memcache->set(array(
9369            'key' => "pc_wp_change_{$apiToken}",
9370            'value' => array('change' => true),
9371            'expire' => 3600 // 1 hr
9372        ));
9373        
9374        $redirectUrl = myTools::getUrl(). "/{$this->localizeDir}" . '/payment/wp_credit_change_form';
9375        return $this->redirect($redirectUrl); 
9376
9377        $this->render('/payment/wp_payment_credit_change');
9378    }
9379    /**
9380     * @api {get}/:language/payment/wp_credit_change_form wp_credit_change_form()
9381     * @apiName wp_credit_change_form
9382     * @apiGroup Payment
9383     * @apiDescription This endpoint is used to display the credit card information change page.
9384     * 
9385     * @apiParam {String} language Language code of the user
9386     * 
9387     * @apiSuccess {View} Render Displays the credit card information change page.
9388     * 
9389     * @apiError {View} Redirect Redirects to {{ENV}}/ if memcache credit change is not set.
9390     * 
9391     * @apiSuccessExample Success Response:
9392     * Display the credit card information change page.
9393     * 
9394     * @apiErrorExample Error Response:
9395     * Redirects to {{ENV}}/ if memcache credit change is not set.
9396     * 
9397     * @apiSampleRequest off
9398     */
9399    public function wp_credit_change_form() {
9400
9401        $this->blockWithdrawnSapuriToS();
9402        $this->disablePageForSapuri();
9403        $this->response->disableCache();
9404        $formType = Configure::read('payment_credit_change');
9405        $this->checkUser($formType);
9406        $apiToken = $this->sharedUserData['User']['api_token'];
9407        $user = $this->sharedUserData['User'];
9408        
9409        $memKey = "pc_wp_change_{$apiToken}";
9410        // redirect to mypage if memcache credit change is not set
9411
9412        if (!$this->memcache->get($memKey)) {
9413            return $this->redirect('/');
9414        }
9415
9416        $isCardRegistered = (!empty($user['card_brand']) && !empty($user['card_number'])) ? true : false;
9417
9418        $this->set('isCardRegistered', $isCardRegistered);
9419        $this->set('cardNumber', $user['card_number']);
9420        $this->set('cardBrand', $user['card_brand']);
9421        $this->set('cardLogo', myTools::getWorldpayCardLogo($user['card_brand']));
9422
9423        // set view vars
9424        $this->set('pmtValue', 'auth');
9425        $this->set('apiToken', $apiToken);
9426        $this->set('logFileName', 'card_change');
9427        $this->set('nc_terminal_type', 1); // pc
9428        $this->set('memKeyError', 'pc_wp_change_error_' . $apiToken);
9429        $this->set('referrer', urlencode(myTools::getUrl(). "/{$this->localizeDir}/payment/payment_credit_change"));
9430        $this->set('successUrl', urlencode(myTools::getUrl()."/{$this->localizeDir}/payment/payment_credit_change_complete"));
9431        $this->set('formType', Configure::read('payment_credit_change'));
9432    }
9433
9434    /**
9435     * @api {post} /:language/payment/payment_credit_charge/:cc payment_credit_charge()
9436     * @apiName payment_credit_charge
9437     * @apiGroup Payment
9438     * @apiDescription This endpoint is used to display the credit card charge page.
9439     * 
9440     * @apiParam {String} language Language code of the user
9441     * @apiParam {String} cc Campaign code/ Blank if no campaign code
9442     * 
9443     * @apiSuccess {View} Render Displays the credit card charge page.
9444     * @apiSuccess {View} Redirect Redirect to zeus credit charge function if currency is equals to jpy.
9445     * @apiSuccess {View} Redirect Redirect to wp credit charge function if currency is not equals to jpy.
9446     * 
9447     * @apiSuccessExample Success Response:
9448     * Display the credit card charge page.
9449     * 
9450     * @apiSuccessExample Success Response jpy currency:
9451     * Redirect to zeus credit charge function.
9452     * 
9453     * @apiSuccessExample Success Response not jpy currency:
9454     * Redirect to wp credit charge function.
9455     * 
9456     * @apiSampleRequest off
9457     */
9458    public function payment_credit_charge() {
9459        $this->blockWithdrawnSapuriToS();
9460        $this->disablePageForSapuri();
9461        $this->checkUser(Configure::read('payment_credit_force_charge'));
9462        $this->set('monthlyPriceSymbol', myTools::getCurrencySymbol($this->sharedUserData['User']['currency_code']));
9463        $userData = $this->sharedUserData['User'];
9464        $userObj = new UserTable($userData);
9465
9466        // NJ-68818: check if payment was charged after challenge already
9467        $this->checkIfChargedAfterChallenge($userData['id'], 'rejoin');
9468        
9469        // NC-8697: delete from deactivated user list
9470        $memCached = new myMemcached();
9471        $memCached->delete('deactivated-user-'.$this->sharedUserData['User']['id']);
9472        UserTable::deleteUserDeactivationLock($this->sharedUserData['User']['id']);
9473        
9474        // NC-7644
9475        $get_params = $this->params->query;
9476        $campaign_code = isset($get_params['cc']) ? $get_params['cc'] : '';
9477        $get_params = (!empty($campaign_code)) ? '?cc='.$campaign_code : '';
9478        $this->set('get_campain_params', $get_params);
9479        if ($campaign_code) {
9480            /* NC-7644 insert to memCached unique mem id */ 
9481            $memCached->set(array(
9482                'key' => 'campaign_code_CC_RE10' . $this->Auth->user('id'),
9483                'value' => true
9484            ));
9485        }else {
9486            if (!$this->request->is('post')) {
9487                // get the campaign `CC_RE10` unique memCached
9488                $memKey = 'campaign_code_CC_RE10' . $this->Auth->user('id');
9489                $memCached->delete($memKey);
9490            }
9491        }
9492
9493        $this->setPerMonthSymbol($this->localizeDir, true);
9494
9495        // NJ-32737
9496        $this->setCouponUseData($this->sharedUserData['User']['id'], $this->sharedUserData['User']['currency_code']);
9497
9498        // redirect to zeus if currency is equals to jpy
9499        if ($this->sharedUserData['User']['currency_code'] == Configure::read('default.user_currency')) {
9500            $this->zeus_credit_charge();
9501        // redirect to wp
9502        } else {
9503            $this->wp_credit_charge();
9504        }
9505
9506        // NJ-30828: set view to display user's paypal email
9507        $this->setPaypalUser($userData);
9508    }
9509
9510    private function zeus_credit_charge() {
9511        $formType = Configure::read('payment_credit_force_charge');
9512        $user = $this->sharedUserData['User'];
9513        $currencyCode = $user['currency_code'];
9514        $logFileName = 'card_charge';
9515
9516        // get premium payment plan data
9517        $ppData = $this->PaymentPlanPrice->getPaymentData(array(
9518            'currencyCode' => $currencyCode,
9519            'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
9520            'logFileName' => $logFileName
9521        ));
9522
9523        #chocotto plan data
9524        $chocottoPlanData = $this->PaymentPlanPrice->getPaymentData(array(
9525            'currencyCode' => $user['currency_code'],
9526            'paymentPlanId' => Configure::read('payment_plans.chocotto_plan'),
9527            'logFileName' => $logFileName ?? 'card_reregister'
9528        ));
9529
9530        // - set chocotto plan price
9531        $this->set('chocottoMonthlyPrice',$chocottoPlanData['fAmount']);
9532        $this->set('chocottoMonthlyPriceNoTax', myTools::formatAmount($chocottoPlanData['amountConstTaxDeducted']));
9533
9534        // - NJ-23812
9535        if ($this->Session->read('credit_skip_to_confirmation')) {
9536            $this->Session->delete('credit_skip_to_confirmation');
9537        }
9538
9539        if ($this->Session->read('paypalPaymentCreditChargeData')){
9540            $this->Session->delete('paypalPaymentCreditChargeData');
9541        }
9542
9543        // redirect to top page if premium payment plan is not supported
9544        if (!$ppData) {
9545            return $this->redirect(myTools::getUrl() . '/');
9546        }
9547
9548        $corporateIndiUser = false;
9549        $corporateUser = isset($user['corporate_id']) && $user['corporate_id'] ? true : false;
9550        
9551        // get corporate payment method
9552        $this->Corporate->openDBReplica();
9553        $corporateData = $this->Corporate->find('first', array(
9554            'fields' => array('payment_method'),
9555            'conditions' => array('id' => $user['corporate_id']),
9556            'recursive' => -1
9557        ));
9558        $this->Corporate->closeDBReplica();
9559
9560        $corporateData = $corporateData ? $corporateData['Corporate'] : null;
9561
9562        // if corporate is individual payment
9563        if ($corporateUser && $corporateData && $corporateData['payment_method'] == 1) {
9564
9565            // get corporate plan data
9566            $cpData = $this->getCorporatePaymentPlan($user);
9567            // return to top page if not supported
9568            if (!$cpData) {
9569                return $this->redirect(myTools::getUrl() . '/');
9570            }
9571
9572            $cfAmount = $cpData['fAmount'];
9573            $corporateIndiUser = $cpData['corporateIndiUser'];
9574        }
9575
9576        // data needed for corporate individual
9577        if ($corporateIndiUser) {
9578            // NJ-28462
9579            $this->corpIndividualData($user);
9580        }
9581
9582        // NC-3914
9583        $this->getAndSetCardInfo($user);
9584
9585        // NC-4926
9586        $isFamilyPlanBefore = PaymentTable::checkIfFamilyPlan(
9587            $user['id'],
9588            $user['hash16'],
9589            array(
9590                Configure::read('payment_credit_family_free'),
9591                Configure::read('payment_credit_family_monthly_payment')
9592            )
9593        );
9594
9595        $this->set('isFamilyPlanBefore', $isFamilyPlanBefore);
9596        $corpSessionKey = 'PaymentCreditChargeCorporateData';
9597
9598        // get reserve payment receivable
9599        $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($user['id']);
9600
9601        // get live lesson payment receivable
9602        $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($user['id'], false, Configure::read('appreciation_data.payment_element_type'));
9603
9604        // get live lesson payment receivable
9605        $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($user['id'], false, Configure::read('payment_element_type.live'));
9606
9607        $annualDiscountOptionData = $this->DiscountOptionsPrice->getPaymentData(['currencyCode' => $user['currency_code'], 'discountOptionId' => Configure::read('discount_option.annual.plan_id')]);
9608
9609        $corporateTaxRate = Configure::read('tax.increase');
9610
9611        // - check if there is annual discount option data
9612        if ($annualDiscountOptionData) {
9613            unset($annualDiscountOptionData['contract_start']);
9614            $annualDiscountOptionData += [
9615                'dosh_event' => Configure::read('discount_option.dosh_event.annual_discount'),
9616                'dosh_status' => Configure::read('discount_option.dosh_status.monthly_discount')
9617            ];
9618
9619            $annualDiscountOptionAmount = $annualDiscountOptionData['amount'];
9620        }
9621
9622        $monthlyPriceWithAnnualDiscount = $ppData['amount'] - $annualDiscountOptionAmount;
9623        $monthlyPriceWithAnnualDiscountNoTax = $monthlyPriceWithAnnualDiscount / $corporateTaxRate;
9624        $monthlyPriceWithAnnualDiscountNoTax = round($monthlyPriceWithAnnualDiscountNoTax);
9625
9626        $this->set('enableAnnualDiscountOption', $annualDiscountOptionData ? true : false);
9627        $this->set('annualDiscountOptionAmount', myTools::formatAmount($annualDiscountOptionAmount));
9628        $this->set('monthlyPriceWithAnnualDiscount', myTools::formatAmount($monthlyPriceWithAnnualDiscount));
9629        $this->set('monthlyPriceWithAnnualDiscountNoTax', myTools::formatAmount($monthlyPriceWithAnnualDiscountNoTax));
9630
9631        # check if post
9632        if ($this->request->is('post')) {
9633            $data = $this->request->data;
9634
9635            // NJ-32737
9636            $couponData = $this->Session->read('apply_coupon_usage_data');
9637
9638            // redirect to paypal confirm page if payment gateway selected is paypal
9639            if ($data['payment_gateway_type'] == Configure::read('card_company.paypal')) {
9640                $data['paymentPlanData'] = $ppData;
9641                $data['receivablePayment'] = $receivablePayment;
9642                $data['appreciationReceivable'] = $appreciationReceivable;
9643                $data['liveLessonReceivable'] = $liveLessonReceivable;
9644                $data['formType'] = $formType;
9645
9646                if ($annualDiscountOptionData) {
9647                    $user['discountOption'] = $annualDiscountOptionData;
9648                }
9649
9650                // NJ-32737
9651                $membershipStatusIndex = UserTable::getStudentMembershipStatus($user['id']);
9652                if (in_array($membershipStatusIndex, Configure::read('allow_coupon.settlement')) &&
9653                    isset($data['z_payment_form_type']) &&
9654                    in_array($data['z_payment_form_type'], Configure::read('allow_coupon.settlement_form_type'))
9655                ) {
9656                    if (isset($couponData['useCouponAmount']) && $couponData['useCouponAmount'] > 0) {
9657                        if ($data['ZPaymentFullLogs']['money'] >= $couponData['useCouponAmount']) {
9658                            $data['ZPaymentFullLogs']['money'] -= $couponData['useCouponAmount'];
9659                        } else {
9660                            $data['ZPaymentFullLogs']['money'] = 0;
9661                        }
9662
9663                        $data['couponUseSettlement'] = $couponData;
9664                    }
9665                }
9666                // NJ-32737-end
9667
9668                $this->Session->write('paypalPaymentCreditChargeData', $data);
9669                return $this->redirect(myTools::getUrl() . '/payment/paypal_payment_credit_charge_confirm');
9670            }
9671
9672            // delete payment gateway type memcache
9673            $this->memcache->delete('creditChargePaymentGatewayType_' . $user['api_token']);
9674
9675            if( isset($data['ZPaymentFullLogs']['corporatePlan']) ) {
9676                if($data['ZPaymentFullLogs']['corporatePlan'] == 'light') {
9677                    $getPaymentPlanId = $this->getCorporatePaymentPlan($user,array('corporate_type' => 4));
9678                    $getLightCorporateData = $this->Corporate->getCorporateLightUserMonthly(array(
9679                        'user_id' => $user['id'],
9680                        'remove_heavy_flg' => true
9681                    ));
9682                    $paymentLightAmount = isset($getLightCorporateData['total']) ? $getLightCorporateData['total'] : 0;
9683                    $basicLightFee = isset($getLightCorporateData['basic_fee']) ? $getLightCorporateData['basic_fee'] : 0;
9684                    $lessonLightFee = isset($getLightCorporateData['lesson_fee']) ? $getLightCorporateData['lesson_fee'] : 0;
9685                    $basicLightFeeWoTax = isset($getLightCorporateData['basic_fee_discounted']) ? $getLightCorporateData['basic_fee_discounted'] : 0;
9686                    $freeLightNumber = isset($getLightCorporateData['fee_charge_count']) ? $getLightCorporateData['fee_charge_count'] : 0;
9687                    $isLightFreeFlg = isset($getLightCorporateData['free_charge_flg']) ? $getLightCorporateData['free_charge_flg'] : false;
9688                    $monthlyLightFee = isset($getLightCorporateData['monthly_fee_wo_tax']) ? $getLightCorporateData['monthly_fee_wo_tax'] : 0;
9689                    $cfLightAmount = myTools::formatAmount($basicLightFeeWoTax);
9690                    $cLightRawAmount = $basicLightFeeWoTax;
9691                    $lessonLightLimit = $this->Corporate->getLessonLimit($user['corporate_id']);
9692                    $cpData = array(
9693                        'basicFee' => $basicLightFee,
9694                        'lessonFee' => $lessonLightFee,
9695                        'freeFlg' => $isLightFreeFlg,
9696                        'freeNumber' => $freeLightNumber,
9697                        'monthlyFee' => $monthlyLightFee,
9698                        'fAmount' => $cfLightAmount,
9699                        'paymentAmount' => $paymentLightAmount,
9700                        'lessonLimit' => $lessonLightLimit,
9701                        'paymentPlanId' => $getPaymentPlanId['paymentPlanId'],
9702                        'cRawAmount'    => $cLightRawAmount,
9703                        'basicFeeWoTax' => $basicLightFeeWoTax,
9704                        'priceId'        => $getPaymentPlanId['priceId']
9705                    );
9706    
9707                    $data['ZPaymentFullLogs']['indiCorpType'] = 4;
9708                } else if($data['ZPaymentFullLogs']['corporatePlan'] == 'premium') {
9709                    $cpPremuimData = $this->getCorporatePaymentPlan($user,array('corporate_type' => 2));
9710                    
9711                    $cdrPremiumParam = array('corporateId' => $user['corporate_id'], 'corporateType' => 2);
9712                    $discountPremium = (int)$this->CorporateDiscountRate->getDiscount($cdrPremiumParam);
9713                    $cPremiumAmount = (int)$cpPremuimData['amount'] - $discountPremium;
9714                    $cPremiumRawAmount = $cPremiumAmount;
9715                    $cfPremiumAmount = myTools::formatAmount($cPremiumAmount);
9716                    $cpData = array(
9717                        'cprAmount' => $cpPremuimData['amount'],
9718                        'cprDiscount' => $discountPremium,
9719                        'paymentAmount' => $cPremiumAmount * $corporateTaxRate,
9720                        'fAmount' => $cfPremiumAmount,
9721                        'cRawAmount' => $cPremiumRawAmount,
9722                        'ppAmount' => $cpPremuimData,
9723                        'paymentPlanId' => $cpPremuimData['paymentPlanId'],
9724                        'priceId'        => $cpPremuimData['priceId']
9725                    );
9726    
9727                    $data['ZPaymentFullLogs']['indiCorpType'] = 2;
9728                } else {
9729                    $cpStandardData = $this->getCorporatePaymentPlan($user,array('corporate_type' => 1));
9730                    $cdrStandardParam = array('corporateId' => $user['corporate_id'], 'corporateType' => 1);
9731                    $discountStandard = (int)$this->CorporateDiscountRate->getDiscount($cdrStandardParam);
9732                    $cStandardAmount = (int)$cpStandardData['amount'] - $discountStandard;
9733                    $cStandardRawAmount = $cStandardAmount;
9734                    $cfStandardAmount = myTools::formatAmount($cStandardAmount);
9735                    $cpData = array(
9736                        'cprAmount' => $cpStandardData['amount'],
9737                        'cprDiscount' => $discountStandard,
9738                        'paymentAmount' => $cStandardAmount * $corporateTaxRate,
9739                        'fAmount' => $cfStandardAmount,
9740                        'cRawAmount' => $cStandardRawAmount,
9741                        'ppAmount' => $cpStandardData,
9742                        'paymentPlanId' => $cpStandardData['paymentPlanId'],
9743                        'priceId'        => $cpStandardData['priceId']
9744                    );
9745                    $data['ZPaymentFullLogs']['indiCorpType'] = 1;
9746                }
9747                $data['ZPaymentFullLogs']['formType'] = $formType = myTools::getCorporateCompanyCardFormType($cpData['paymentPlanId']);
9748
9749                $corpIndiPrices = $this->Session->read('corporateIndiPrices');
9750                $corpIndiPrices[$data['ZPaymentFullLogs']['corporatePlan']]['plan_type'] = $data['ZPaymentFullLogs']['indiCorpType'];
9751                $this->Session->write($corpSessionKey,$corpIndiPrices[$data['ZPaymentFullLogs']['corporatePlan']]);
9752            }
9753
9754            $data['ZPaymentFullLogs']['clientip'] = Configure::read('ZEUS_clientip');
9755            $data['ZPaymentFullLogs']['telno'] = Configure::read('credit.default_telno');
9756            
9757
9758            if ($this->Session->read('PaymentCreditChargeInfo')) {
9759                $this->Session->delete('PaymentCreditChargeInfo');
9760            }
9761
9762            // - set lite plan flag 
9763            $litePlanFlg = false;
9764
9765            // - set chocotto plan flag 
9766            $chocottoPlanFlg = false;
9767
9768            // - NJ-18780 : check if lite plan type for normal user 
9769            if (
9770                isset($data['ZPaymentFullLogs']['payment_plan_type']) && 
9771                !$corporateIndiUser
9772            ) {
9773                $paymentPlanType = $data['ZPaymentFullLogs']['payment_plan_type'];
9774                $litePlanFlg = ((int) $data['ZPaymentFullLogs']['payment_plan_type']  == 1) ? true : false;
9775                $chocottoPlanFlg = ((int) $data['ZPaymentFullLogs']['payment_plan_type']  == Configure::read('register_plan_types.chocotto'));
9776                if ($litePlanFlg) {
9777                    $_plan_id = Configure::read('payment_plans.light_plan');
9778                    $formType = myTools::getLitePlanUserFormType($_plan_id);
9779                } elseif ($chocottoPlanFlg) {
9780                    $_plan_id = Configure::read('payment_plans.chocotto_plan');
9781                    $formType = Configure::read('payment_credit_chocotto_force_charge');
9782                }else{
9783                    $_plan_id = Configure::read('payment_plans.premium_plan');
9784                    $formType = Configure::read('payment_credit_force_charge');
9785                }
9786
9787                // fetch light plan description
9788                $litePlanData = $this->PaymentPlanPrice->getPaymentData(array(
9789                    'currencyCode' => $currencyCode,
9790                    'paymentPlanId' => $_plan_id,
9791                    'logFileName' => $logFileName
9792                ));
9793
9794                if (!$litePlanData) {
9795                    $this->set('transactionError', 1);
9796                }else{
9797
9798                    // - check if not annual discount option
9799                    if (isset($data['ZPaymentFullLogs']['payment_plan_type']) && $data['ZPaymentFullLogs']['payment_plan_type'] == 0) {
9800                        $annualDiscountOptionAmount = 0;
9801                    }
9802
9803                    // - set light amount 
9804                    $lightPlanAmount = $litePlanData['amount'];
9805
9806                    $data['ZPaymentFullLogs']['light_plan_amount'] = $litePlanData['amount'];
9807                    $data['ZPaymentFullLogs']['light_plan_price_id'] = $litePlanData['priceId'];
9808
9809                    // change payment plan id and price id
9810                    $user['price_id'] = $litePlanData['priceId'];
9811                    $user['payment_plan_id'] = $litePlanData['paymentPlanId'];
9812                    $user['paymentAmount'] = $lightPlanAmount + $receivablePayment + $appreciationReceivable + $liveLessonReceivable - $annualDiscountOptionAmount;
9813
9814                    // change the money 
9815                    $data['ZPaymentFullLogs']['money'] = $litePlanData['amount'];
9816                    $data['ZPaymentFullLogs']['formType'] = $formType;
9817
9818                    // add annual discount option
9819                    if (
9820                        $annualDiscountOptionData &&
9821                        $paymentPlanType == Configure::read('register_plan_types.premium_with_annual_discount_option')
9822                    ) {
9823                        $data['discountOption'] = $user['discountOption'] = $annualDiscountOptionData;
9824                    }
9825
9826                    // NJ-32737
9827                    $membershipStatusIndex = UserTable::getStudentMembershipStatus($user['id']);
9828                    if (in_array($membershipStatusIndex, Configure::read('allow_coupon.settlement')) &&
9829                        isset($data['z_payment_form_type']) &&
9830                        in_array($data['z_payment_form_type'], Configure::read('allow_coupon.settlement_form_type'))
9831                    ) {
9832                        if (isset($couponData['useCouponAmount']) && $couponData['useCouponAmount'] > 0) {
9833                            if ($data['ZPaymentFullLogs']['money'] >= $couponData['useCouponAmount']) {
9834                                $data['ZPaymentFullLogs']['money'] -= $couponData['useCouponAmount'];
9835                            } else {
9836                                $data['ZPaymentFullLogs']['money'] = 0;
9837                            }
9838
9839                            $user['couponUseSettlement'] = $couponData;
9840
9841                            // payment amount - coupon amount
9842                            $user['paymentAmount'] = $data['ZPaymentFullLogs']['money'];
9843
9844                        }
9845                    }
9846                    // NJ-32737-end
9847
9848                    $npt = $this->createPaymentTransaction($formType, $user);
9849                    
9850                    // 
9851                    if ($npt) {
9852                        // add payment hash
9853                        $data['ZPaymentFullLogs']['paymentHash'] = $npt['payment_hash'];
9854                    }else{
9855                        $this->set('transactionError', 1);
9856                    }
9857                }
9858
9859            }else{
9860                $npt = true;
9861            }
9862
9863            if($corporateIndiUser) {
9864                if ($corporateIndiPaymentData = $this->Session->read('PaymentCreditChargeCorporateData')) {
9865                    $corporatePaymentAmount = $corporateIndiPaymentData['paymentAmount'];
9866                    $data['ZPaymentFullLogs']['money'] = (int)$corporatePaymentAmount;
9867                }
9868            }
9869
9870            $this->log(__METHOD__ . '[NJ-18780] > form type ' . json_encode($formType), 'paypal_debug');
9871            $this->log(__METHOD__ . '[NJ-18780] > data '. json_encode($data), 'paypal_debug');
9872
9873            if ($npt) {
9874
9875                // NJ-25522: Skip confirm page if using 3D secure challenge
9876                $zeus3DSecureChallengeFlg = $this->memcache->get('zeus3DSecureChallengeFlg_' . $user['id']);
9877
9878                $user['price_id'] = $ppData['priceId'];
9879                $user['payment_plan_id'] = $ppData['paymentPlanId'];
9880                $user['paymentAmount'] = $ppData['amount'] + $receivablePayment + $appreciationReceivable + $liveLessonReceivable - $annualDiscountOptionAmount;
9881
9882                if(!$zeus3DSecureChallengeFlg && $corporateIndiUser) {
9883                    $corpIndiPT = $this->createCorporateIndividualPayment($data);
9884                    $data['ZPaymentFullLogs']['paymentHash'] = $corpIndiPT['paymentHash'];
9885                    $data['ZPaymentFullLogs']['money'] = $corpIndiPT['paymentAmount'];
9886                }
9887
9888                $this->Session->write('PaymentCreditChargeInfo', $data);
9889
9890                if ($zeus3DSecureChallengeFlg) {
9891                    $formType = isset($data['ZPaymentFullLogs']['formType']) ? $data['ZPaymentFullLogs']['formType'] : Configure::read('payment_credit_force_charge');
9892
9893                    if($corporateIndiUser) {
9894                        $data['ZPaymentFullLogs']['paymentHash'] = $this->Session->read('indiCorpPaymentHash') ?? '';
9895                    }
9896
9897                    // if corporate credit charge
9898                    if (
9899                        $formType != Configure::read('payment_credit_force_charge') && 
9900                        !$litePlanFlg &&
9901                        !$chocottoPlanFlg
9902                    ) {
9903                        if ($corporateIndiPaymentData = $this->Session->read('PaymentCreditChargeCorporateData')) {
9904                            $corporatePaymentAmount = $corporateIndiPaymentData['paymentAmount'];
9905                            $data['ZPaymentFullLogs']['money'] = (int)$corporatePaymentAmount;
9906                        }
9907                    }
9908                    $referrer = array('controller' => 'Payment', 'action' => 'payment_credit_charge');
9909                    $this->z_start($data, $formType, $referrer);
9910                }
9911
9912                // - NJ-23812: write session to skip and auto charge check
9913                $this->Session->write('credit_skip_to_confirmation',true);
9914                return $this->redirect(myTools::getUrl() . '/payment/payment_credit_charge_confirm');
9915            }
9916
9917        } else {
9918            $data = $this->Session->read('PaymentCreditChargeInfo');
9919            $this->set('data', $data);
9920        }
9921
9922        // clear previously set tokens and set new token
9923        $this->unsetToken();
9924        $token = md5 (uniqid (rand (), true));
9925        $this->Session->write('Payment.token', $token);
9926        $comPlanUser = false;
9927        $isFreeFlg = false;
9928        $freeNumber = 0;
9929        $userId = $user['id'];
9930
9931        // if has complimentary code
9932        if (isset($user['complimentary_code'])) {
9933            // set com_plan_user to true if payment plan id is not null and is complimentary plan
9934            if (isset($user['payment_plan_id']) && $user['payment_plan_id'] == Configure::read('payment_plans.complimentary_plan')){
9935                $comPlanUser = $user['com_plan_user'] = true;
9936            // set com_plan_user to true if payment plan id is null and is complimentary plan
9937            } elseif (!isset($user['payment_plan_id']) && $this->Payment->ifComPlanUser($user['id'])) {
9938                $comPlanUser = $user['com_plan_user'] = true;
9939            }
9940        }
9941    
9942        // delete session
9943        if ($this->Session->check($corpSessionKey)) {
9944            $this->Session->delete($corpSessionKey);
9945        }
9946
9947        // check if corporate user
9948        if (!$corporateIndiUser) {
9949            // change payment plan id and price id
9950            $user['price_id'] = $ppData['priceId'];
9951            $user['payment_plan_id'] = $ppData['paymentPlanId'];
9952            $user['paymentAmount'] = $ppData['amount'] + $receivablePayment + $appreciationReceivable + $liveLessonReceivable;
9953
9954            $user = $this->changePaymentPlanIfTelecomUser($user);
9955
9956            // - NJ-23812: write session to skip and auto charge check
9957            // set transaction error to 1 if failed to create payment transaction
9958            if (!$pt = $this->createPaymentTransaction($formType, $user)) {
9959                $this->set('transactionError', 1);
9960            }
9961        }
9962        
9963        if (isset($cpData)) {
9964            $this->set('cpFormatAmount', $cfAmount);
9965            // $this->set('cRawAmount',$cRawAmount);
9966        }
9967
9968        // -------  NJ-23812 : set support skip paypal confirmation
9969
9970        $sessionPaypalParams = array(
9971            'token' => $token,
9972            'payment_gateway_type' => Configure::read('card_company.paypal'),
9973            'ZPaymentFullLogs' => array(
9974                'retainIndiPlan' => $corporateIndiUser,
9975                'paymentHash' => isset($pt['payment_hash']) ? $pt['payment_hash'] : "",
9976                'money' => $ppData['amount']
9977            ),
9978            'paymentPlanData' => $ppData,
9979            'receivablePayment' => $receivablePayment,
9980            'appreciationReceivable' => $appreciationReceivable,
9981            'liveLessonReceivable' => $liveLessonReceivable,
9982            'formType' => $formType
9983        );
9984
9985        $this->Session->write('paypalPaymentCreditChargeData', $sessionPaypalParams);
9986
9987        $this->setSupportPayPal($user);
9988        $this->set('paypalUserData', $user);
9989        $this->set('userApiToken', $user['api_token']);
9990
9991        $currencyData = $this->Currency->getSymbolAndPosition($user['currency_code']);
9992        $this->set('monthlyPrice',myTools::customFormatAmount($ppData['amount'], $user['currency_code']));
9993        $this->set('monthylyPriceNoTax', myTools::formatAmount($ppData['amountConstTaxDeducted']));
9994        $this->set('monthlyPriceSymbol',myTools::getCurrencySymbol($user['currency_code']));
9995
9996        // ----------- NJ-23812 : support end 
9997
9998        $this->set('ppAmount', $ppData['amount']);
9999        $this->set('ppFormatAmount', $ppData['fAmount']);
10000        $this->set('corporateIndiUser', $corporateIndiUser);
10001        $this->set('comPlanUser', $comPlanUser);
10002        $this->set('token', $token);
10003        $this->set('title_for_layout', '再入会手続き|オンライン英会話のネイティブキャンプ');
10004        $this->set('zeusTransactionFlag', true);
10005        $this->set('paymentHash', isset($pt['payment_hash']) ? $pt['payment_hash'] : "");
10006        $this->set('corporateType', myTools::getCoporateTypeUsingPaymentPlanId($user['payment_plan_id']));
10007        $this->set('isFreeFlg', $isFreeFlg);
10008        $this->set('freeNumber', $freeNumber);
10009        $this->set('currencyCode', $currencyCode);
10010        $this->setPaymentViewVars();
10011        
10012        $comp_plan_page = 'credit_charge';
10013        if ($comPlanUser) {
10014            $comp_plan_page = "not_allowed_lite_plan_change";
10015            $ccData = $this->ComplimentaryCode->find('first', 
10016            array(
10017                'fields' => array('available_days','template_type'),
10018                'conditions' => array(
10019                    'code' => $user['complimentary_code'],
10020                    'template_type !=' => 0 // not trial
10021                )
10022            ));
10023
10024            if ($ccData) {
10025                $comp_plan_page = 'credit_charge';
10026            }
10027
10028            $this->User->clear();
10029        
10030            $_paymentPlanID =     $this->User->read(array('payment_plan_id'), $user['id']);
10031            $_paymentPlanID = $_paymentPlanID['User']['payment_plan_id'];
10032
10033            // -> update the correct complimentary payment plan id
10034            $user['payment_plan_id'] = $_paymentPlanID;
10035        }
10036
10037        // - NJ-18780 : set view var for lite plan description 
10038        $this->setLitePaymentInfoView($user,true,false,$comp_plan_page);
10039
10040        if ($this->RequestHandler->isMobile()) {
10041            $this->layout = ('mobile');
10042            $this->render('/Mobile/Payment/payment_credit_charge');
10043        }
10044    }
10045
10046    private function wp_credit_charge() {
10047        // set variables
10048        $userData = $this->sharedUserData['User'];
10049        $apiToken = $userData['api_token'];
10050        $memKey = "pc_wp_charge_card_type_{$apiToken}";
10051        $memData = $this->memcache->get($memKey);
10052        $cardType = isset($memData['cardType']) ? $memData['cardType'] : 0;
10053
10054        // - NJ-23812
10055        if ($this->Session->read('credit_skip_to_confirmation')) {
10056            $this->Session->delete('credit_skip_to_confirmation');
10057        }
10058
10059        // redirect to form page if previously child and parent unsubsribed
10060        if ( 
10061            (empty($userData['card_company']) && empty($userData['card_brand']) && empty($userData['card_token']) && empty($userData['card_number'])) ||
10062            ($userData['card_brand'] == 'AFTEE2' && empty($userData['card_company']))
10063        ) {
10064            $this->memcacheCardType(array(
10065                'key' => $memKey,
10066                'value' => array('cardType' => $cardType)
10067            ));
10068            return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/payment/wp_credit_charge_form");
10069        }
10070
10071        // get payment data
10072        $pData = $this->PaymentPlanPrice->getPaymentData(array(
10073            'currencyCode' => $userData['currency_code'],
10074            'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
10075            'logFileName' => 'card_charge'
10076        ));
10077
10078        // redirect to mypage if premium plan payment is not supported
10079        if (!isset($pData)) {
10080            return $this->redirect('/');
10081        }
10082
10083        if ($this->request->is('post')) {
10084            $cardType = $this->request->data['cardType'];
10085
10086            // memcache card type value
10087            $this->memcacheCardType(array(
10088                'key' => $memKey,
10089                'value' => array('cardType' => $cardType)
10090            ));
10091
10092            // redirect to hosted page if using new card ($cardType = 1)
10093            if ($cardType) {
10094                return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/payment/wp_credit_charge_form");
10095            // redirect to confirm page if using existing card ($cardType = 0)
10096            } else {
10097
10098                // - NJ-23812: write session to skip and auto charge 
10099                $this->Session->write('credit_skip_to_confirmation',true);
10100
10101                return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/payment/payment_credit_charge_confirm");
10102            }
10103        }
10104
10105        /* check if there is error during payment process */
10106        if ($errorType = isset($this->request->query['wpErrType']) ? $this->request->query['wpErrType'] : null) {
10107            if ($error = myTools::getWorldpayErrorMsg($errorType)) {
10108                $this->set('error', $error);
10109            }
10110        } else {
10111            $memKeyError = 'pc_wp_charge_error_'. $apiToken;
10112            if ($error = $this->memcache->get($memKeyError)) {
10113                $this->set('error', $error);
10114
10115                // delete memcache error
10116                $this->memcache->delete($memKeyError);
10117            }
10118        }
10119
10120        // check if allowed aftee
10121        $this->checkAfteeSupported($this->sharedUserData['User'],true);
10122    
10123            // set view variables
10124        $this->set('pmtValue', 'payment');
10125        $this->set('apiToken', $apiToken);
10126        $this->set('logFileName', 'card_charge');
10127        $this->set('nc_terminal_type', 1); // pc
10128        $this->set('memKeyError', 'pc_wp_charge_error_'.$apiToken);
10129        $this->set('formType', Configure::read("payment_credit_force_charge"));
10130        $this->set('referrer', urlencode(myTools::getUrl(). "/{$this->localizeDir}/payment/payment_credit_charge"));
10131        $this->set('successUrl', urlencode( myTools::getUrl() . "/{$this->localizeDir}/payment/payment_credit_charge_complete"));
10132
10133        $isCardRegistered = (!empty($userData['card_brand']) && !empty($userData['card_number'])) ? true : false;
10134
10135        // ------- end NJ-23812 ------------------------------
10136
10137        // set view variables
10138        $this->set('comPlanUser', $this->ifComPlanUser($userData));
10139        $this->set('cardLogo', myTools::getWorldpayCardLogo($userData['card_brand']));
10140        $this->set('cardType', $cardType);
10141        $this->set('cardBrand', $userData['card_brand']);
10142        $this->set('cardNumber', $userData['card_number']);
10143        $this->set('fAmount', $pData['fAmount']);
10144        $this->set('ppAmount', $pData['amount']);
10145        $this->set('isCardRegistered', $isCardRegistered);
10146
10147        $currencyData = $this->Currency->getSymbolAndPosition($userData['currency_code']);
10148        $this->set('monthlyPrice', myTools::customFormatAmount($pData['amount'], $userData['currency_code']));
10149        $this->set('monthylyPriceNoTax', myTools::formatAmount($pData['amountConstTaxDeducted']));
10150        $this->set('monthlyPriceSymbol',myTools::getCurrencySymbol($userData['currency_code']));
10151
10152
10153        if ($this->RequestHandler->isMobile()) {
10154            $this->layout = ('mobile');
10155            $this->render('/Mobile/Payment/wp_payment_credit_charge');
10156        } else {
10157            $this->render('/Payment/wp_payment_credit_charge');
10158        }
10159    }
10160    /**
10161     * @api {get} /:language/payment/payment_credit_charge_confirm payment_credit_charge_confirm()
10162     * @apiName payment_credit_charge_confirm
10163     * @apiGroup Payment
10164     * @apiDescription This endpoint is used to display the payment confirmation page for credit charge.
10165     * 
10166     * @apiParam {String} language Language code of the user
10167     * 
10168     * @apiSuccess {View} Render Displays the payment confirmation page for credit charge.
10169     * @apiSuccess {View} Redirect Redirect to zeus credit charge confirm function if currency is equals to jpy.
10170     * @apiSuccess {View} Redirect Redirect to wp credit charge confirm function if currency is not equals to jpy.
10171     * 
10172     * @apiSuccessExample Success Response:
10173     * Display the payment confirmation page for credit card payment.
10174     * 
10175     * @apiSuccessExample Redirect Response if currency is equals to jpy:
10176     * Redirect to zeus_credit_charge_confirm() function.
10177     * 
10178     * @apiSuccessExample Redirect Response if currency is not equals to jpy:
10179     * Redirect to wp_credit_charge_confirm() function.
10180     * 
10181     * @apiSampleRequest off
10182     */
10183    public function payment_credit_charge_confirm() {
10184        $this->checkUser(Configure::read('payment_credit_force_charge'));
10185
10186        // redirect to zeus process if currency is equals to jpy
10187        if ($this->sharedUserData['User']['currency_code'] == Configure::read('default.user_currency')) {
10188            $this->zeus_credit_charge_confirm();
10189        // redirect to wp
10190        } else {
10191            $this->wp_credit_charge_confirm();
10192        }
10193
10194    }
10195
10196    /**
10197     * @api {post} /payment/retrial_confiscate_coins/:formType/:userId/:paymentPlanId retrial_confiscate_coins()
10198     * @apiName retrial_confiscate_coins
10199     * @apiGroup Payment
10200     * @apiDescription This endpoint is used to confiscate coins for retrial users.
10201     * 
10202     * @apiParam {String} formType Form type of the user
10203     * @apiParam {Number} userId User ID of the user
10204     * @apiParam {Number} paymentPlanId Payment plan ID of the user
10205     * 
10206     * @apiSuccess {Boolean} true Returns true if the coins are confiscated successfully.
10207     *
10208     * @apiError {Boolean} false Returns false if the coins are not confiscated successfully.
10209     * 
10210     * @apiSuccessExample Success Response:
10211     * true
10212     * 
10213     * @apiErrorExample Error Response:
10214     * false
10215     */
10216    public function retrial_confiscate_coins($params = []) {
10217
10218        if (
10219            isset($params['formType']) &&
10220            isset($params['userId']) &&
10221            isset($params['paymentPlanId']) &&
10222            (
10223                (    $params['formType'] == Configure::read('payment_credit_authentication') &&
10224                    $params['paymentPlanId'] = Configure::read('payment_plans.free_trial')
10225                ) || 
10226                (
10227                    $params['formType'] == Configure::read('payment_lite_credit_free') &&
10228                    $params['paymentPlanId'] = Configure::read('payment_plans.light_plan_free')
10229                )
10230            )
10231        ) {
10232
10233            $reEnroll = $this->UsersDeactivationEnquate->find('first', [
10234                'fields' => array('membership_type', 'deactivation_type'),
10235                'conditions' => array(
10236                    'UsersDeactivationEnquate.user_id' => $params['userId'],
10237                    'OR' => array(
10238                        'UsersDeactivationEnquate.membership_type' => [
10239                            Configure::read('student_status_type.sapuri'),
10240                            Configure::read('student_status_type.card_auth')
10241                        ],
10242                        'UsersDeactivationEnquate.deactivation_type' => Configure::read('deactivation_type.retrial_grantee')
10243                        )
10244                ),
10245                'order' => 'UsersDeactivationEnquate.created DESC'
10246            ]);
10247
10248            if (!empty($reEnroll)) {
10249
10250                // Step 1: Retrieve the user's current MC coin balance
10251                $_monthlyPoints = $this->UsersPoint->getCurrentUserMCPoint($params['userId']); // MC = Monthly Coin
10252
10253                // Step 2: Confiscate existing MC coins if the user has a positive balance
10254                if (is_numeric($_monthlyPoints) && (int) $_monthlyPoints > 0) {
10255                    $_confiscateParams = array(
10256                        'userId' => $params['userId'],
10257                        'point' => $_monthlyPoints,
10258                        'kbn' => 18, // Administrator Change/Minus
10259                        'coinType' => 3
10260                    );
10261
10262                    // Apply the confiscation of MC coins
10263                    $this->UsersPoint->confiscateUserLitePoints($_confiscateParams);
10264                }
10265
10266                // Step 3: Grant bonus coins as part of re-enrollment (retrial)
10267                $reEnroll = $reEnroll['UsersDeactivationEnquate'];
10268
10269                UsersPointTable::giveBonusCoins([
10270                    'userId' => $params['userId'],
10271                    'triggerNo' => 5,
10272                    'usersDeactivationEnquateMembershipType' => isset($reEnroll['membership_type']) && $reEnroll['membership_type'] ? $reEnroll['membership_type'] : null,
10273                    'adminGrantRetrial' => $reEnroll['deactivation_type'] == '2' ? true : false
10274                ]);
10275            }
10276        }
10277    }
10278
10279
10280
10281    private function zeus_credit_charge_confirm() {
10282        // redirect to top page if zeuspay info does not exist
10283        if (!$data = $this->Session->read('PaymentCreditChargeInfo')) {
10284            return $this->redirect(myTools::getUrl() . '/');
10285        }
10286
10287        $isFreeFlg = false;
10288        $lessonLimit = 0;
10289        $monthlyFee = 0;
10290        $freeNumber = 0;
10291        $retainAsCorporateUser = false;
10292        $indiCorpTypeLight = false;
10293        $fAmount = myTools::formatAmount($data['ZPaymentFullLogs']['money']);
10294        $corporatePaymentAmount = 0;
10295        $userData = $this->sharedUserData['User'];
10296
10297        // if corporate and retain corporate individual plan
10298        if (isset($userData['corporate_id']) && $userData['corporate_id']) {
10299            $retainAsCorporateUser = true;
10300            // get corporate user session data
10301            if ($corporateIndiPaymentData = $this->Session->read('PaymentCreditChargeCorporateData')) {
10302                $fAmount = $corporateIndiPaymentData['fAmount'];
10303                $corporatePaymentAmount = $corporateIndiPaymentData['paymentAmount'];
10304
10305                // if corporate light
10306                if ($data['ZPaymentFullLogs']['indiCorpType'] == Configure::read('corporate_type.light')) {
10307                    $indiCorpTypeLight = true;
10308                    $isFreeFlg = $corporateIndiPaymentData['freeFlg'];
10309                    $monthlyFee = $corporateIndiPaymentData['monthlyFee'];
10310                    $freeNumber = $corporateIndiPaymentData['freeNumber'];
10311                    $lessonLimit = $corporateIndiPaymentData['lessonLimit'];
10312                }
10313            }
10314        }
10315
10316        $readSkipConfirmation = $this->Session->read('credit_skip_to_confirmation');
10317
10318        if ($readSkipConfirmation) {
10319            $this->Session->delete('credit_skip_to_confirmation');
10320        }
10321
10322        if ($this->request->is('post') || $readSkipConfirmation) {
10323            // check if token matches token in session
10324            $checkToken = $this->checkToken($data['token']);
10325
10326            // check if token is true
10327            if ($checkToken) {
10328                // unset previously set tokens
10329                $this->unsetToken();
10330                $formType = isset($data['ZPaymentFullLogs']['formType']) ? $data['ZPaymentFullLogs']['formType'] : Configure::read('payment_credit_force_charge');
10331
10332                $isLitePlan = (isset($data['ZPaymentFullLogs']['payment_plan_type']) && (int) $data['ZPaymentFullLogs']['payment_plan_type'] == 1) ? true : false;
10333
10334                $isChocottoPlan = (
10335                    isset($data['ZPaymentFullLogs']['payment_plan_type']) &&
10336                    $data['ZPaymentFullLogs']['payment_plan_type'] == Configure::read('register_plan_types.chocotto')
10337                );
10338
10339                // if corporate credit charge
10340                if ($formType != Configure::read('payment_credit_force_charge') && !$isLitePlan && !$isChocottoPlan) {
10341                    $data['ZPaymentFullLogs']['money'] = (int)$corporatePaymentAmount;
10342                }
10343
10344                $referrer = array('controller' => 'Payment', 'action' => 'payment_credit_charge');
10345                $this->z_start($data, $formType, $referrer);
10346            }
10347        }
10348
10349        if (isset($data['ZPaymentFullLogs']['cardnumber']) && !empty($data['ZPaymentFullLogs']['cardnumber'])) {
10350            $cardNumberArr = str_split($data['ZPaymentFullLogs']['cardnumber'], 4);
10351            $this->set('cardNumber', end($cardNumberArr));
10352        } else {
10353            $this->getAndSetCardInfo($userData);
10354        }
10355
10356        // - set view vars
10357        $this->set('monthlyPriceSymbol', myTools::getCurrencySymbol($userData['currency_code']));
10358        $this->set('fAmount', $fAmount);
10359        $this->set('indiCorpTypeLight', $indiCorpTypeLight);
10360        $this->set('lessonLimit', $lessonLimit);
10361        $this->set('isFreeFlg', $isFreeFlg);
10362        $this->set('freeNumber', $freeNumber);
10363        $this->set('monthlyFee', $monthlyFee);
10364        $this->set('corporateType', $data['ZPaymentFullLogs']['indiCorpType']);
10365        $this->set('retainAsCorporateUser', $retainAsCorporateUser);
10366
10367        if ($this->RequestHandler->isMobile()) {
10368            $this->layout = ('mobile');
10369            $this->render('/Mobile/Payment/payment_credit_charge_confirm');
10370        }
10371    }
10372
10373    private function wp_credit_charge_confirm() {
10374        $this->response->disableCache();
10375        // set variables
10376        $logFileName = 'card_charge';
10377        $formType = Configure::read('payment_credit_force_charge');
10378        $userData = $this->sharedUserData['User'];
10379        $currencyCode = $userData['currency_code'];
10380        $userId = $userData['id'];
10381        $apiToken = $userData['api_token'];
10382
10383        $readSkipConfirmation = $this->Session->read('credit_skip_to_confirmation');
10384        if ($readSkipConfirmation){
10385            $this->Session->delete('credit_skip_to_confirmation');
10386        }
10387
10388        $memKey = "pc_wp_charge_card_type_{$apiToken}";
10389        // redirect to mypage if memcache card type is not set
10390        if (!$this->memcache->get($memKey)) {
10391            return $this->redirect('/');
10392        }
10393
10394        // get payment data
10395        $pData = $this->PaymentPlanPrice->getPaymentData(array(
10396            'currencyCode' => $currencyCode,
10397            'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
10398            'logFileName' => $logFileName
10399        ));
10400
10401        // redirect to mypage if premium plan not supported
10402        if (!$pData) {
10403            return $this->redirect('/');
10404        }
10405
10406        $userData['com_plan_user'] = $this->ifComPlanUser($userData);
10407        $userData['payment_plan_id'] = $pData['paymentPlanId'];
10408        $userData['price_id'] = $pData['priceId'];
10409        $memKeySkipCharge = "pc_wp_charge_card_type_skip_confirm_{$apiToken}";
10410
10411        if ($this->request->is('post') || $readSkipConfirmation) {
10412            // get reserve payment receivable
10413            $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userId);
10414
10415            // get appreciation payment receivable
10416            $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('appreciation_data.payment_element_type'));
10417
10418            // get live lesson payment receivable    
10419            $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.live'));
10420
10421            // add force charge payment and receivable payment amount
10422            $totalAmount = $pData['amount'] + $receivablePayment + $appreciationReceivable + $liveLessonReceivable;
10423
10424            // NJ-32737
10425            $couponData = $this->Session->read('apply_coupon_usage_data');
10426
10427            $membershipStatusIndex = UserTable::getStudentMembershipStatus($userData['id']);
10428            if (in_array($membershipStatusIndex, Configure::read('allow_coupon.settlement')) &&
10429                isset($formType) &&
10430                in_array($formType, Configure::read('allow_coupon.settlement_form_type'))
10431            ) {
10432                if (isset($couponData['useCouponAmount']) && $couponData['useCouponAmount'] > 0) {
10433                    if ($totalAmount >= $couponData['useCouponAmount']) {
10434                        $totalAmount -= $couponData['useCouponAmount'];
10435                    } else {
10436                        $totalAmount = 0;
10437                    }
10438
10439                    $userData['couponUseSettlement'] = $couponData;
10440                }
10441            }
10442            // NJ-32737-end
10443
10444            $paymentMethodType = myTools::getWPPaymentMethodType($userData['card_brand'], 'payment');
10445            $merchantCode = myTools::getWPMerchantCode($paymentMethodType);
10446            $paymentMethod = explode('_', $paymentMethodType);
10447            $paymentMethod = isset($paymentMethod[0]) ? $paymentMethod[0] : null;
10448            $orderCode = myTools::generateOrderCode($userId);
10449            $currencyExponents = Configure::read('worldpay.currency_exponents');
10450            $exponent = $currencyExponents[$currencyCode];
10451
10452            // get total amount with checking currency exponent
10453            $totalAmountArr = myTools::wpGetAmount($exponent, $totalAmount);
10454            $ncAmount = $totalAmountArr['ncAmount'];
10455            $wpAmount = $totalAmountArr['wpAmount'];
10456
10457            $wpData = array(
10458                'cardToken' => $userData['card_token'],
10459                'merchantCode' => $merchantCode,
10460                'paymentHash' => $orderCode,
10461                'wpPaymentAmount' => $wpAmount
10462            );
10463
10464            // set payment amount
10465            $userData['paymentAmount'] = $ncAmount;
10466
10467            // create payment transaction
10468            if (!$pt = $this->createPaymentTransaction($formType, $userData, $wpData)) {
10469                $this->log(__METHOD__ .' Failed to save payment transaction. Params --> ' . json_encode($wpData), $logFileName);
10470                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to save payment transaction. Params --> ' . json_encode($wpData), 'error');
10471                return $this->redirect('/');
10472            }
10473
10474            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - After save payment transaction. Params --> ' . json_encode($wpData), 'error');
10475
10476            // if aftee payment
10477            if ($userData['card_company'] == Configure::read('card_company.aftee') || ($userData['card_brand'] == "AFTEE" && !empty($userData['aftee_transaction_identifier']))) {
10478
10479                if (!class_exists('AfteePaymentService')) {
10480                    App::uses('AfteePaymentService','Lib');
10481                }
10482                $afteeService = new AfteePaymentService();
10483                $afteeChecksumData = array(
10484                    'shopItemId' => "AFTEE" . $formType,
10485                    'itemName' => 'CreditForceChargeUsingExistingCard',
10486                    'itemPrice' => $totalAmount,
10487                    'itemCount' => 1,
10488                    'customerPhoneNumber' => $userData['phone_number'],
10489                    'customerEmail' => $userData['email'],
10490                    'shopTransactionNo' => $orderCode,
10491                    'userID' =>  $userData['id']
10492                );
10493                $checksum = $afteeService->generateChecksum($afteeChecksumData, false);
10494                $afteeData = array(
10495                    'authentication_token' => $userData['card_token'],
10496                    'related_id' => $userData['aftee_transaction_identifier'],
10497                    'checksum' => $checksum['checksum'],
10498                    'shop_transaction_no' => $orderCode,
10499                    'transaction_options' => array(1)
10500                );
10501        
10502                $afteePaymentData = array_merge($afteeData, $checksum['settlementData']);
10503    
10504                // aftee execute payment
10505                $receivableResult = $afteeService->directPayment($afteePaymentData);
10506                $checkRes = json_decode($receivableResult, true);
10507
10508
10509                if ( isset($checkRes['object']) && $checkRes['object'] == 'transaction') {
10510                    $prPaymentSuccess = true;
10511                } else if ( !array_key_exists("object", $checkRes) || (isset($checkRes['object']) && $checkRes['object'] == 'error')) {
10512                    $prPaymentSuccess = false;
10513                }
10514
10515                // set user model
10516                $uModel = $this->User;
10517                $dataSource = $uModel->getDataSource();
10518                $dataSource->begin();
10519
10520                $afteeTransactionIdentifier = isset($checkRes['id']) && !empty($checkRes['id']) ? $checkRes['id'] : NULL;
10521                if (isset($checkRes['related_transaction']) && !empty($checkRes['related_transaction'])) {
10522                    $afteeTransactionIdentifier = $checkRes['related_transaction'];
10523                }
10524                $orderCode = isset($checkRes['shop_transaction_no']) && !empty($checkRes['shop_transaction_no']) ? $checkRes['shop_transaction_no'] : NULL;
10525                $checkRes['OrderCode'] = $orderCode;
10526
10527                // payment transaction additional data
10528                $checkRes['OrderCode'] = $orderCode;
10529                $checkRes['authentication_token'] = $userData['card_token'];
10530                $checkRes['customer']['phone_number'] = $userData['phone_number'];
10531
10532                // process payment data
10533                if ($prPaymentSuccess) {
10534                    $afteeParams = array(
10535                        'data' => $checkRes,
10536                        'ptData' => $pt,
10537                        'logFileName' => $logFileName,
10538                        'dataSource' => $dataSource,
10539                        'amount' => $pData['amount'],
10540                        'userData' => $userData,
10541                        'receivablePayment' => $receivablePayment,
10542                        'appreciationReceivable' => $appreciationReceivable,
10543                        'liveLessonReceivable' => $liveLessonReceivable,
10544                        'transactionIdentifier' => $afteeTransactionIdentifier,
10545                        'aftee' => 1
10546                    );
10547    
10548                    $this->processAfteePayment($afteeParams);
10549                }
10550
10551                // update payment transaction
10552                $updateData = array(
10553                    'id' => $pt['id'],
10554                    'fields' => array(
10555                        'status' => $prPaymentSuccess,
10556                        'response_text' => array('aftee_directPayment_response' => $receivableResult))
10557                );
10558
10559                // update payment transaction
10560                $this->PaymentTransaction->updateAfteePaymentTransaction($updateData);
10561
10562
10563                // redirect to payment_credit_charge with error display if direct payment response is not authorised
10564                if (!$prPaymentSuccess) {
10565                    if (!class_exists('myMemcached')) {
10566                        App::uses('myMemcached', 'Lib');
10567                    }
10568                    $memKeyError = 'pc_wp_charge_error_' . $apiToken;
10569                    $memerror = __('トランザクションを完了できません。 もう一度お試しください。');
10570                    $memcached = new myMemcached();
10571                    $memcached->set(array(
10572                        'key' => $memKeyError,
10573                        'value' => $memerror,
10574                        'expire' => 3600 // 1 hour
10575                    ));
10576                    return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/payment/payment_credit_charge");
10577                }
10578
10579
10580            // default worldpay payment
10581            } else {
10582
10583                $wpData = array(
10584                    'merchantCode' => $merchantCode,
10585                    'orderCode' => $orderCode,
10586                    'description' => 'Credit Force Charge Using Existing Card',
10587                    'currencyCode' => $currencyCode,
10588                    'exponent' => $exponent,
10589                    'amount' => $wpAmount,
10590                    'cardToken' => $userData['card_token'],
10591                    'email' => $userData['email'],
10592                    'authenticatedShopperId' => $userId,
10593                    'xmlName' => 'direct_payment_with_token',
10594                    'shopperIpAddress' => $_SERVER["REMOTE_ADDR"],
10595                    'wpTransactionIdentifier' => $userData['wp_transaction_identifier'],
10596                    'paymentMethod' => $paymentMethod
10597                );
10598
10599                $result = wpPaymentService::directPayment($wpData);
10600
10601                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - directPayment result --> ' . json_encode($result), 'error');
10602
10603                $updateData = array(
10604                    'id' => $pt['id'],
10605                    'fields' => array('response_text' => array('directPayment_response' => $result)),
10606                    'logFileName' => $logFileName
10607                );
10608
10609                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - before updatePaymentTransaction result --> ' . json_encode($updateData), 'error');
10610
10611                // update payment transaction direct response.
10612                $this->updatePaymentTransaction($updateData);
10613
10614                // redirect to payment_credit_charge with error display if direct payment response is not authorised
10615                if (!myTools::checkIfWPPaymentResponseIsAuthorised($result)) {
10616                    $params = array(
10617                        'apiToken' => $apiToken,
10618                        'wpResponse' => $result,
10619                        'memKey' => 'pc_wp_charge_error_' . $apiToken
10620                    );
10621                    myTools::parseAndSetWPErrorResponse($params);
10622                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - WP Payment not authorised --> ' . json_encode($params), 'error');
10623                    return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/payment/payment_credit_charge");
10624                }
10625            }
10626
10627            //    NC-7644 Add code reward for re-enroolling with the campaign code
10628            $this->addCoinRewardForReenroll($userData);
10629            
10630            // Teacher Perks : Student re-enroll
10631            ClassRegistry::init('TeacherPerksAccount')->reEnroll(['user_id' => $userData['id']]);
10632
10633            // delete memcache
10634            if ($this->memcache->get($memKey)) {
10635                $this->memcache->delete($memKey);
10636            }
10637
10638            // redirect to complete page
10639            return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/payment/payment_credit_charge_complete");
10640        }
10641
10642        $this->set('monthlyPriceSymbol', myTools::getCurrencySymbol($currencyCode));
10643        $currencyData = $this->Currency->getSymbolAndPosition($currencyCode);
10644        $this->set('monthylyPrice', myTools::addPriceSymbol($pData['fAmount'], $currencyData['symbol'], $currencyData['prefix_suffix_flg']));
10645
10646        // set view variables
10647        $this->set('currencyCode', $currencyCode);
10648        $this->set('cardLogo', myTools::getWorldpayCardLogo($userData['card_brand']));
10649        $this->set('cardBrand', $userData['card_brand']);
10650        $this->set('cardNumber', $userData['card_number']);
10651        $this->set('fAmount', $pData['fAmount']);
10652        $this->set('cardCompany', $userData['card_company']);
10653
10654        if ($this->RequestHandler->isMobile()) {
10655            $this->layout = ('mobile');
10656            $this->render('/Mobile/Payment/wp_payment_credit_charge_confirm');
10657        } else {
10658            $this->render('/Payment/wp_payment_credit_charge_confirm');
10659        }
10660    }
10661    /**
10662     * @api {get} /:language/payment/paypal_payment_credit_charge_confirm paypal_payment_credit_charge_confirm()
10663     * @apiName paypal_payment_credit_charge_confirm
10664     * @apiGroup Payment
10665     * @apiDescription This endpoint is used to display the payment confirmation page for credit charge using paypal.
10666     * 
10667     * @apiParam {String} language Language code of the user
10668     * 
10669     * @apiSuccess {View} Render Displays the payment confirmation page for credit charge using paypal.
10670     * 
10671     * @apiError {View} Redirect Redirect to mypage if paypal payment credit charge data is missing.
10672     * 
10673     * @apiSuccessExample Success Response:
10674     * Display the payment confirmation page for credit card payment using paypal.
10675     * 
10676     * @apiErrorExample Error Response:
10677     * Redirect to mypage if paypal payment credit charge data is missing.
10678     * 
10679     * @apiSampleRequest off
10680     */
10681    public function paypal_payment_credit_charge_confirm() {
10682        $logFileName = 'paypal_debug';
10683        $user = $this->sharedUserData['User'];
10684
10685        $data = $this->Session->read('paypalPaymentCreditChargeData');
10686        if (!$data) {
10687            $this->log(__METHOD__ . ' Missing paypal payment credit charge data. --> ' . json_encode($data) . ' | user id  --> ' . json_encode($user['id']), $logFileName);
10688            return $this->redirect(myTools::getUrl());
10689        }
10690
10691        $this->set('fAmount', myTools::formatAmount($data['ZPaymentFullLogs']['money']));
10692        $this->set('monthlyPriceSymbol', myTools::getCurrencySymbol($user['currency_code']));
10693        $this->set('paypalUserData', $user);
10694        $this->set('userApiToken', $user['api_token']);
10695
10696        // set payment gateway type
10697        $this->memcache->set(array(
10698            'key' => 'creditChargePaymentGatewayType_' . $user['api_token'],
10699            'value' => $data['payment_gateway_type'],
10700            'expire' => 3600 // 1 hour
10701        ));
10702
10703        if ($this->RequestHandler->isMobile()) {
10704            $this->layout = ('mobile');
10705            $this->render('/Mobile/Payment/paypal_payment_credit_charge_confirm');
10706        }
10707    }
10708    /**
10709     * @api {get} /:language/payment/wp_credit_charge_form wp_credit_charge_form()
10710     * @apiName wp_credit_charge_form
10711     * @apiGroup Payment
10712     * @apiDescription This endpoint is used to redirect to pages after form submission for worldpay credit charge.
10713     * 
10714     * @apiParam {String} language Language code of the user
10715     * 
10716     * @apiSuccess {View} Redirect Redirects to {{ENV}}/payment/payment_credit_charge_complete if the user is not on a complimentary plan.
10717     * @apiSuccess {View} Redirect Redirects to {{ENV}}/payment/coupon_payment_credit_charge_complete if the user is on a complimentary plan.
10718     * 
10719     * @apiError {View} Redirect Redirects to mypage if memcache card type is not set.
10720     * @apiError {View} Redirect Redirects to mypage if premium plan payment is not supported.
10721     * 
10722     * @apiSuccessExample Success Response if user is not on a complimentary plan:
10723     * Redirects to {{ENV}}/payment/payment_credit_charge_complete.
10724     * 
10725     * @apiSuccessExample Success Response if user is on a complimentary plan:
10726     * Redirects to {{ENV}}/payment/coupon_payment_credit_charge_complete.
10727     * 
10728     * @apiErrorExample Error Response if memcache card type is not set:
10729     * Redirects to mypage.
10730     * 
10731     * @apiErrorExample Error Response if premium plan payment is not supported:
10732     * Redirects to mypage.
10733     * 
10734     * @apiSampleRequest off
10735     */
10736    public function wp_credit_charge_form() {
10737        $this->response->disableCache();
10738        $formType = Configure::read('payment_credit_force_charge');
10739        $this->checkUser($formType);
10740        $apiToken = $this->sharedUserData['User']['api_token'];
10741        $userData = $this->sharedUserData['User'];
10742
10743        $memKey = "pc_wp_charge_card_type_{$apiToken}";
10744        // redirect to mypage if memcache card type is not set
10745        if (!$this->memcache->get($memKey)) {
10746            return $this->redirect('/');
10747        }
10748
10749        // - NJ-23812
10750        if ($this->Session->read('credit_skip_to_confirmation')) {
10751            $this->Session->delete('credit_skip_to_confirmation');
10752        }
10753
10754        $this->setPerMonthSymbol($this->localizeDir, true);
10755
10756        // get payment data
10757        $pData = $this->PaymentPlanPrice->getPaymentData(array(
10758            'currencyCode' => $userData['currency_code'],
10759            'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
10760            'logFileName' => 'card_charge'
10761        ));
10762
10763        // redirect to mypage if premium plan payment is not supported
10764        if (!isset($pData)) {
10765            return $this->redirect('/');
10766        }
10767
10768        // check if allowed aftee
10769        $this->checkAfteeSupported($this->sharedUserData['User']);
10770
10771
10772        // - NJ-23812 start support
10773        /* check if there is error during payment process */
10774        if ($errorType = isset($this->request->query['wpErrType']) ? $this->request->query['wpErrType'] : null) {
10775            if ($error = myTools::getWorldpayErrorMsg($errorType)) {
10776                $this->set('error', $error);
10777            }
10778        } else {
10779            $memKeyError = 'pc_wp_charge_error_'. $apiToken;
10780            if ($error = $this->memcache->get($memKeyError)) {
10781                $this->set('error', $error);
10782
10783                // delete memcache error
10784                $this->memcache->delete($memKeyError);
10785            }
10786        }
10787
10788        $comPlanUser = $this->ifComPlanUser($userData);
10789
10790        // set view variables
10791        $this->set('comPlanUser', $comPlanUser);
10792        $this->set('cardLogo', myTools::getWorldpayCardLogo($userData['card_brand']));
10793        $this->set('cardType', $cardType);
10794        $this->set('cardBrand', $userData['card_brand']);
10795        $this->set('cardNumber', $userData['card_number']);
10796        $this->set('fAmount', $pData['fAmount']);
10797        $this->set('ppAmount', $pData['amount']);
10798
10799        $isCardRegistered = (!empty($userData['card_brand']) && !empty($userData['card_number'])) ? true : false;
10800        $this->set('isCardRegistered', $isCardRegistered);
10801
10802
10803        $currencyData = $this->Currency->getSymbolAndPosition($userData['currency_code']);
10804        $this->set('monthlyPrice', myTools::customFormatAmount($pData['amount'], $userData['currency_code']));
10805        $this->set('monthylyPriceNoTax', myTools::formatAmount($pData['amountConstTaxDeducted']));
10806        $this->set('monthlyPriceSymbol',myTools::getCurrencySymbol($userData['currency_code']));
10807
10808        // set view variables
10809        $this->set('pmtValue', 'payment');
10810        $this->set('apiToken', $apiToken);
10811        $this->set('logFileName', 'card_charge');
10812        $this->set('nc_terminal_type', 1); // pc
10813        $this->set('memKeyError', 'pc_wp_charge_error_'.$apiToken);
10814        $this->set('formType', $formType);
10815        $this->set('referrer', urlencode(myTools::getUrl(). "/{$this->localizeDir}/payment/payment_credit_charge"));
10816
10817        // NJ-32737
10818        $this->setCouponUseData($this->sharedUserData['User']['id'], $this->sharedUserData['User']['currency_code']);
10819
10820        // if complimentary plan user
10821        if ($this->ifComPlanUser($this->sharedUserData['User'])) {
10822            $this->set('successUrl', urlencode(myTools::getUrl()."/{$this->localizeDir}/payment/coupon_payment_credit_charge_complete"));
10823        } else {
10824            $this->set('successUrl', urlencode(myTools::getUrl()."/{$this->localizeDir}/payment/payment_credit_charge_complete"));
10825        }
10826        if ($this->RequestHandler->isMobile()) {
10827            $this->layout = ('mobile');
10828            $this->render('/Mobile/Payment/wp_payment_credit_charge');
10829        } 
10830    }
10831    /**
10832     * @api {get} /:language/payment/paypal_payment_credit_charge_process/:token/:negativeTesting/:payment_plan_type paypal_payment_credit_charge_process()
10833     * @apiName paypal_payment_credit_charge_process
10834     * @apiGroup Payment
10835     * @apiDescription This endpoint is used to process the credit charge using paypal.
10836     * 
10837     * @apiParam {String} language Language code of the user
10838     * @apiParam {String} token Token of the user
10839     * @apiParam {Number} negativeTesting Negative testing flag. 1 = true, 0 = false
10840     * @apiParam {Number} payment_plan_type Payment plan type.
10841     * 
10842     * @apiSuccess {View} Redirect Redirects to {{ENV}}/payment/payment_credit_charge_complete if the payment is successful.
10843     * 
10844     * @apiError {View} Redirect Redirects to {{ENV}}/mypage if missing paypal credit charge data
10845     * @apiError {View} Redirect Redirects to {{ENV}}/payment/payment_credit_charge if failed to fetch light plan description
10846     * @apiError {View} Redirect Redirects to {{ENV}}/ if annual discount option does not exist or is not enabled
10847     * @apiError {View} Redirect Redirects to {{ENV}}/payment/payment_credit_charge if failed to fetch chocotto plan description
10848     * @apiError {View} Redirect Redirects to {{ENV}}/payment/payment_credit_charge if paypal settlement is not successful
10849     * 
10850     * @apiSuccessExample Success Response:
10851     * Redirects to {{ENV}}/payment/payment_credit_charge_complete if the payment is successful.
10852     * 
10853     * @apiErrorExample Error Response if missing paypal credit charge data:
10854     * Redirects to {{ENV}}/mypage.
10855     * 
10856     * @apiErrorExample Error Response if failed to fetch light plan description:
10857     * Redirects to {{ENV}}/payment/payment_credit_charge.
10858     * 
10859     * @apiErrorExample Error Response if annual discount option does not exist or is not enabled:
10860     * Redirects to {{ENV}}/.
10861     * 
10862     * @apiErrorExample Error Response if failed to fetch chocotto plan description:
10863     * Redirects to {{ENV}}/payment/payment_credit_charge.
10864     * 
10865     * @apiErrorExample Error Response if paypal settlement is not successful:
10866     * Redirects to {{ENV}}/payment/payment_credit_charge.
10867     * 
10868     * @apiSampleRequest off
10869     */
10870    public function paypal_payment_credit_charge_process() {
10871        $this->autoRender = false;
10872        $this->layout = false;
10873
10874        $logFileName = 'paypal_debug';
10875        $user = $this->sharedUserData['User'];
10876        $userId = $user['id'];
10877        $get = $this->request->query;
10878        $formType = Configure::read('payment_credit_force_charge');
10879
10880        // get session payment credit register data
10881        $data = $this->Session->read('paypalPaymentCreditChargeData');
10882
10883        // redirect to top page if empty
10884        if (!$data) {
10885            $this->log(__METHOD__ . ' Missing paypal payment credit charge data. --> ' . json_encode($data) . ' | user id  --> ' . json_encode($userId), $logFileName);
10886            return $this->redirect(myTools::getUrl());
10887        }
10888
10889        $paymentPlanType = isset($get['payment_plan_type']) ? $get['payment_plan_type'] : 0;
10890
10891        //- pass original payment plan
10892        $userObj = new UserTable($user);
10893        $user['original_status_index'] = $userObj->getMembershipTypeIndex();
10894
10895        if ($paymentPlanType == Configure::read('register_plan_types.light')) {
10896
10897            // fetch light plan description
10898            $litePlanData = $this->PaymentPlanPrice->getPaymentData(array(
10899                'currencyCode' => $user['currency_code'],
10900                'paymentPlanId' => Configure::read('payment_plans.light_plan'),
10901                'logFileName' => 'card_reregister'
10902            ));
10903
10904            if (!$litePlanData) {
10905                $this->Session->setFlash('決済失敗', array("element" => "flashfail"));
10906
10907                $memKey = 'paypalBillingAgreementData_' . $get['token'];
10908
10909                // delete memcache billing agreement data
10910                if ($this->memcache->get($memKey)) {
10911                    $this->memcache->delete($memKey);
10912                }
10913
10914                return $this->redirect(myTools::getUrl('payment/payment_credit_charge'));
10915            }
10916        
10917            $user['price_id'] = $litePlanData['priceId'];
10918            $user['payment_plan_id'] = $litePlanData['paymentPlanId'];
10919        
10920            // - update data 
10921            $data['ZPaymentFullLogs']['money'] = $litePlanData['amount'];
10922            $data['paymentPlanData'] = $litePlanData;
10923            $data['formType'] =  myTools::getLitePlanUserFormType($litePlanData['paymentPlanId']);
10924        } elseif ($paymentPlanType == Configure::read('register_plan_types.premium_with_annual_discount_option')) {
10925            $annualDiscountOptionData = $this->DiscountOptionsPrice->getPaymentData(['currencyCode' => $user['currency_code'], 'discountOptionId' => Configure::read('discount_option.annual.plan_id')]);
10926
10927            // redirect to credit page if annual discount option does not exist or is not enabled
10928            if (!$annualDiscountOptionData) {
10929                return $this->redirect('/');
10930            }
10931
10932            unset($annualDiscountOptionData['contract_start']);
10933            $annualDiscountOptionData += [
10934                'dosh_event' => Configure::read('discount_option.dosh_event.annual_discount'),
10935                'dosh_status' => Configure::read('discount_option.dosh_status.monthly_discount')
10936            ];
10937
10938            // update payment transaction (add annual discount option data)
10939            $this->PaymentTransaction->updatePaymentParams(array('paymentHash' => $data['ZPaymentFullLogs']['paymentHash'], 'updateData' => ['annualDiscountOption' => $annualDiscountOptionData]));
10940
10941            $data['discountOption'] = $annualDiscountOptionData;
10942
10943        //- NJ-27262 chocotto plan payment
10944        } elseif ($paymentPlanType == Configure::read('register_plan_types.chocotto')) {
10945            // fetch chocotto plan description
10946            $chocottoPlanData = $this->PaymentPlanPrice->getPaymentData(array(
10947                'currencyCode' => $user['currency_code'],
10948                'paymentPlanId' => Configure::read('payment_plans.chocotto_plan'),
10949                'logFileName' => 'card_reregister'
10950            ));
10951
10952            if (!$chocottoPlanData) {
10953                $this->Session->setFlash(__d('acount', '決済失敗'), array("element" => "flashfail"));
10954
10955                $memKey = 'paypalBillingAgreementData_' . $get['token'];
10956
10957                // delete memcache billing agreement data
10958                if ($this->memcache->get($memKey)) {
10959                    $this->memcache->delete($memKey);
10960                }
10961
10962                return $this->redirect(myTools::getUrl('payment/payment_credit_charge'));
10963            }
10964        
10965            //- NJ-36141: reset daily lesson time if changed to chocotto plan
10966            $this->UsersDetail->chocottoCampUserDetails($user['id'], true);
10967            
10968            $user['price_id'] = $chocottoPlanData['priceId'];
10969            $user['payment_plan_id'] = $chocottoPlanData['paymentPlanId'];
10970        
10971            // - update data 
10972            $data['ZPaymentFullLogs']['money'] = $chocottoPlanData['amount'];
10973            $data['paymentPlanData'] = $chocottoPlanData;
10974            $data['formType'] =  myTools::getChocottoPlanUserFormType($chocottoPlanData['paymentPlanId']);
10975        }
10976
10977        // NJ-32737
10978        $couponData = $this->Session->read('apply_coupon_usage_data');
10979
10980        if (!empty($couponData['useCouponAmount'])) {
10981            $data['couponUseSettlement'] = $couponData;
10982            $user['couponUseSettlement'] = $couponData;
10983        }
10984
10985        // process paypal settlement
10986        // redirect to charge page if return is false
10987        if ((isset($get['negativeTesting']) && $get['negativeTesting']) || !$this->processPayPalPayment($data, $user)) {
10988            $this->Session->setFlash('決済失敗', array("element" => "flashfail"));
10989
10990            $memKey = 'paypalBillingAgreementData_' . $get['token'];
10991
10992            // delete memcache billing agreement data
10993            if ($this->memcache->get($memKey)) {
10994                $this->memcache->delete($memKey);
10995            }
10996
10997            return $this->redirect(myTools::getUrl('payment/payment_credit_charge'));
10998        }
10999
11000        $memKey = 'creditChargePaymentGatewayType_' .$user['api_token'];
11001        // delete memcache payment gateway type
11002        if ($this->memcache->get($memKey)) {
11003            $this->memcache->delete($memKey);
11004        }
11005
11006        // delete session
11007        $this->Session->delete('paypalPaymentCreditChargeData');
11008
11009        // redirect to payment charge complete
11010        return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_charge_complete'));
11011    }
11012
11013    /**
11014     * @api {get} /:language/payment/payment_credit_retry payment_credit_retry()
11015     * @apiName payment_credit_retry
11016     * @apiGroup Payment
11017     * @apiDescription This endpoint is used to process payment credit retry.
11018     * 
11019     * @apiParam {String} language Language code of the user
11020     * 
11021     * @apiSuccess {View} Redirect redirects to zeus credit retry function for currency is equals to jpy
11022     * @apisuccess {View} Redirect redirects to wp credit retry function is non jpy
11023     * 
11024     * @apiSuccessExample Success Response JPY:
11025     * Redirects to zeus credit retry function
11026     * 
11027     * @apiSuccessExample Success Response Non JPY:
11028     * Redirects to wp credit retry function
11029     * 
11030     * @apiSampleRequest off
11031     */
11032    public function payment_credit_retry() {
11033        $this->response->disableCache();
11034        $this->blockWithdrawnSapuriToS();
11035        $this->disablePageForSapuri();
11036        $this->checkUser(Configure::read('payment_credit_retry'));
11037
11038        // NJ-68818: check if payment was charged after challenge already
11039        $this->checkIfChargedAfterChallenge($this->sharedUserData['User']['id'], 'retry');
11040
11041        // redirect to zeus if currency is equals to jpy
11042        if ($this->sharedUserData['User']['currency_code'] == Configure::read('default.user_currency')) {
11043            $this->zeus_credit_retry();
11044        // redirect to wp
11045        } else {
11046            $this->wp_credit_retry();
11047        }
11048
11049        $userData = $this->sharedUserData['User'];
11050        // NJ-30828: set view to display user's paypal email
11051        $this->setPaypalUser($userData);
11052    }
11053
11054    private function zeus_credit_retry() {
11055        $formType = Configure::read('payment_credit_retry');
11056        $logFileName = 'card_retry';
11057        $userData = $this->sharedUserData['User'];
11058
11059        // - reset sessions
11060        if ($this->Session->read('paypalPaymentCreditRetryData')){
11061            $this->Session->delete('paypalPaymentCreditRetryData');
11062        }
11063
11064        // - reset session
11065        if ($this->Session->read('credit_skip_to_confirmation')){
11066            $this->Session->delete('credit_skip_to_confirmation');
11067        }
11068
11069        $data = $this->Session->read('PaymentCreditRetryInfo');
11070        $this->set('data', $data);
11071
11072        // - NJ-18780: check if lite plan user 
11073        $isLitePlanUser = in_array($pData['paymentPlanId'], Configure::read('lite_payment_plans')) ? true : false;
11074
11075        
11076        
11077        // - check price id
11078        if (
11079            (!isset($userData['price_id']) || 
11080            empty($userData['price_id'])) & 
11081            $isLitePlanUser &&
11082            isset($userData['currency_code'])
11083        ) {
11084            $lightPlanData = $this->PaymentPlanPrice->getPaymentData(array(
11085                'currencyCode' => $userData['currency_code'],
11086                'paymentPlanId' => Configure::read('payment_plans.light_plan')
11087            ));
11088
11089            // if empty
11090            if (!$lightPlanData) {
11091                return $this->redirect(myTools::getUrl() . '/');
11092            }
11093            
11094            $userData['price_id'] = $lightPlanData['priceId'];
11095        }
11096
11097        // redirect to my page if empty payment plan data
11098        if (!$pData = $this->getRetryPaymentData($userData, $logFileName)) {
11099            return $this->redirect(myTools::getUrl() . '/');
11100        }
11101
11102        $userData['payment_plan_id'] = $pData['paymentPlanId'];
11103        $userData['price_id'] = $pData['priceId'];
11104        $userId = $userData['id'];
11105        $corporateId = $userData['corporate_id'];
11106        $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($userData['payment_plan_id']);
11107        $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userId);
11108        $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('appreciation_data.payment_element_type') );
11109        $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.live'));
11110        $discountedCoupon = 0;
11111
11112        // NJ-47740 - get monthly reqeust coupon discount
11113        $coupon = $this->UsersCouponV1->getCouponUseRequest(array(
11114            'userId' => $userId,
11115            'kbn' => Configure::read('coupon_kbn.monthly_settlement')
11116        ));
11117        
11118        if (!empty($coupon['amount']) && !empty($coupon['grp_id'])) {
11119            $userData['monthlyDiscount'] = $coupon['amount'];
11120            $userData['monthly_grp_id'] = $coupon['grp_id'];
11121            $discountedCoupon = $coupon['amount'];
11122        }
11123
11124        // get user active annual discount option
11125        $annualDiscountOptionData = $this->UserDiscountOptionsTerm->getTerm([
11126            'user_id' => $userData['id'],
11127            'discount_option_id' => Configure::read('discount_option.annual.plan_id'),
11128            'status' => 1
11129        ]);
11130        $annualDiscountOptionAmount = $annualDiscountOptionData ? $annualDiscountOptionData['amount'] : 0;
11131
11132        // check if post
11133        if ($this->request->is('post')) {
11134            $data = $this->request->data;
11135
11136            // redirect to paypal confirm page if payment gateway selected is paypal
11137            if ($data['payment_gateway_type'] == Configure::read('card_company.paypal')) {
11138                $data['paymentPlanData'] = $pData;
11139                $data['receivablePayment'] = $receivablePayment;
11140                $data['appreciationReceivable'] = $appreciationReceivable;
11141                $data['liveLessonReceivable'] = $liveLessonReceivable;
11142                $data['annualDiscountOptionAmount'] = $annualDiscountOptionAmount;
11143                
11144                //-new chocotto plan
11145                if ($pData['paymentPlanId'] == Configure::read('payment_plans.chocotto_plan')) {
11146                    $formType = Configure::read('payment_credit_chocotto_retry');
11147                }
11148                $data['formType'] = $formType;
11149
11150                if (isset($userData['monthlyDiscount']) && isset($userData['monthly_grp_id'])) {
11151                    $data['monthlyDiscount'] = $userData['monthlyDiscount'];
11152                    $data['monthly_grp_id'] = $userData['monthly_grp_id'];
11153                }
11154
11155                $this->Session->write('paypalPaymentCreditRetryData', $data);
11156                return $this->redirect(myTools::getUrl() . '/payment/paypal_payment_credit_retry_confirm');
11157            }
11158
11159            // delete payment gateway type memcache
11160            $this->memcache->delete('creditRetryPaymentGatewayType_' . $userData['api_token']);
11161
11162            $data['ZPaymentFullLogs']['clientip'] = Configure::read('ZEUS_clientip');
11163            $data['ZPaymentFullLogs']['telno'] = Configure::read('credit.default_telno');
11164
11165            if ($this->Session->read('PaymentCreditRetryInfo')) {
11166                $this->Session->delete('PaymentCreditRetryInfo');
11167            }
11168
11169            $this->Session->write('PaymentCreditRetryInfo', $data);
11170
11171            // NJ-25522: Skip confirm page if using 3D secure challenge
11172            $zeus3DSecureChallengeFlg = $this->memcache->get('zeus3DSecureChallengeFlg_' . $userData['id']);
11173
11174            if ($zeus3DSecureChallengeFlg) {
11175                $formType = Configure::read('payment_credit_retry');
11176                //-new chocotto plan
11177                if ($pData['paymentPlanId'] == Configure::read('payment_plans.chocotto_plan')) {
11178                    $formType = Configure::read('payment_credit_chocotto_retry');
11179                }
11180
11181                $referrer = array('controller' => 'Payment', 'action' => 'payment_credit_retry');
11182                $this->z_start($data, $formType, $referrer);
11183            } else {
11184                $this->Session->write('credit_skip_to_confirmation',true);
11185                return $this->redirect(myTools::getUrl() . '/payment/payment_credit_retry_confirm');
11186            }
11187        }
11188
11189        // clear previously set tokens and set new token
11190        $this->unsetToken();
11191        $token = md5(uniqid(rand(), true));
11192        $this->Session->write('Payment.token', $token);
11193
11194        $lessonFee = $basicFee = 0;
11195        $corporateUser = !empty($corporateId) && !empty($corporateType) ? true : false;
11196        $corpSessionKey = 'PaymentCreditRetryInfoCorporateAmount';
11197
11198        // delete corporate retry session if exist
11199        if ($this->Session->read($corpSessionKey)) {
11200            $this->Session->delete($corpSessionKey);
11201        }
11202
11203        // NJ-23812 : fetch the unformatted amount without tax
11204        $monthlyPriceRaw = 0;
11205
11206        // if corporate user
11207        if ($corporateUser) {
11208            $corporateTaxRate = Configure::read('tax.increase');
11209
11210            // if light
11211            if ($corporateType == Configure::read('corporate_type.light')) {
11212                $getCorpMemberReceivable = $this->CorporatePaymentMemberReceivable->memberReceivable(array('user_id' => $userId));
11213                $lessonFee = isset($getCorpMemberReceivable["lesson_fee"]) ? $getCorpMemberReceivable["lesson_fee"] : 0 ;
11214                $basicFee = isset($getCorpMemberReceivable["basic_fee"]) ? $getCorpMemberReceivable["basic_fee"] : 0 ;
11215                $amountWoTax = isset($getCorpMemberReceivable["basic_fee_wo_tax"]) ? $getCorpMemberReceivable["basic_fee_wo_tax"] : 0 ;
11216                $userData['lesson_fee'] = $lessonFee;
11217                $userData['basic_fee'] = $basicFee;
11218                $pData['amount'] = isset($getCorpMemberReceivable["total"]) ? $getCorpMemberReceivable["total"] : 0;
11219                $pData['fAmount'] = myTools::formatAmount($amountWoTax);
11220                $monthlyPriceRaw = $amountWoTax;
11221                $this->Session->write($corpSessionKey, $pData['fAmount']);
11222                $userData['corporateSettlementType'] = Configure::read('corporate_settlement_types.retry_payment');
11223            // if premium or standard
11224            } elseif (in_array($corporateType, array(Configure::read('corporate_type.premium'), Configure::read('corporate_type.standard')))) {
11225                $unpaidCPRParams = array(
11226                    'userId' => $userId,
11227                    'corporateId' => $corporateId,
11228                    'corporateType' => $corporateType
11229                );
11230
11231                // get unpaid corporate payment receivable
11232                $unpaidCPRData= $this->CorporatesPaymentReceivable->getIndiUnPaidReceivable($unpaidCPRParams);
11233
11234                // generate corporate payment receivable if no unpaid corporate payment receivable
11235                if (!$unpaidCPRData) {
11236                    $corpType = myTools::getCoporateTypeUsingPaymentPlanId($userData['payment_plan_id']);
11237                    $corpTypeStandard = Configure::read('corporate_type.standard');
11238                    $corpTypePremium = Configure::read('corporate_type.premium');
11239
11240                    $cprTypes = array(
11241                        Configure::read('corporate_type.standard') => $this->CorporatesPaymentReceivable->typeCorporateStandard,
11242                        Configure::read('corporate_type.premium') => $this->CorporatesPaymentReceivable->typeCorporatePremium
11243                    );
11244
11245                    // get payment plan data
11246                    $monthlyPaymentData = $this->PaymentPlanPrice->getPaymentData(array(
11247                        'currencyCode' => $userData['currency_code'],
11248                        'paymentPlanId' => $userData['payment_plan_id']
11249                    ));
11250
11251                    $cprDiscount = (int)$this->CorporateDiscountRate->getDiscount(array(
11252                        'corporateId' => $corporateId, 
11253                        'corporateType' => $corpType
11254                    ));
11255
11256                    $insertCPRData = array(
11257                        'corporate_id' => $corporateId,
11258                        'user_id' => $userId,
11259                        'type' => isset($cprTypes[$corpType]) ? $cprTypes[$corpType] : 0,
11260                        'status' => 0, // unpaid
11261                        'quantity' => 1,
11262                        'amount' => $monthlyPaymentData['amount'],
11263                        'discount' => $cprDiscount,
11264                        'next_settlement' => date('Y-m-d 00:00:00')
11265                    );
11266
11267                    $unpaidCPRData = array(
11268                        'amount' => $monthlyPaymentData['amount'],
11269                        'discount' => $cprDiscount
11270                    );
11271
11272                    // create corporate payment receivable
11273                    if (!$this->CorporatesPaymentReceivable->addReceivablePayment($insertCPRData)) {
11274                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to create payment receivable.', $data);
11275                        return ;
11276                    }
11277
11278                }
11279
11280                $cprAmountWoTax = $unpaidCPRData['amount'] - $unpaidCPRData['discount'];
11281                $monthlyPriceRaw = $cprAmountWoTax;
11282                $pData['amount'] = (int)$cprAmountWoTax * $corporateTaxRate;
11283                $pData['fAmount'] = myTools::formatAmount($cprAmountWoTax);
11284                $this->Session->write($corpSessionKey, $pData['fAmount']);
11285                $userData['updateCorporateReceivable'] = true;
11286                $userData['corporateSettlementType'] = Configure::read('corporate_settlement_types.retry_payment');
11287            }
11288        }
11289
11290        // add retry payment, receivable payment amount and live lesson payment 
11291        $userData['paymentAmount'] = $pData['amount'] + $receivablePayment + $appreciationReceivable + $liveLessonReceivable - $annualDiscountOptionAmount - $discountedCoupon;
11292        $userData = $this->changePaymentPlanIfTelecomUser($userData);
11293
11294        if ($annualDiscountOptionData) {
11295            unset($annualDiscountOptionData['contract_start']);
11296            $annualDiscountOptionData += [
11297                'dosh_event' => Configure::read('discount_option.dosh_event.annual_discount'),
11298                'dosh_status' => Configure::read('discount_option.dosh_status.monthly_discount')
11299            ];
11300            $userData['annualDiscountOption'] = $annualDiscountOptionData;
11301        }
11302
11303        //-new chocotto plan
11304        if ($pData['paymentPlanId'] == Configure::read('payment_plans.chocotto_plan')) {
11305            $formType = Configure::read('payment_credit_chocotto_retry');
11306        }
11307
11308        // set transaction error to 1 if failed to create payment transaction
11309        if (!$pt = $this->createPaymentTransaction($formType, $userData)) {
11310            $this->set('transactionError', 1);
11311        }
11312
11313        // NC-3914
11314        $this->getAndSetCardInfo($userData);
11315
11316        $currencyData = $this->Currency->getSymbolAndPosition($userData['currency_code']);
11317        $this->set('monthlyPrice', myTools::addPriceSymbol($pData['fAmount'], $currencyData['symbol'], $currencyData['prefix_suffix_flg']));
11318    
11319        //-new chocotto plan
11320        if ($pData['paymentPlanId'] == Configure::read('payment_plans.chocotto_plan')) {
11321            $formType = Configure::read('payment_credit_chocotto_retry');
11322        }
11323
11324        // ------  NJ-23812 : start support paypal skip confirmation page
11325        $sessionPaypalParams = array(
11326            'payment_gateway_type' => Configure::read('card_company.paypal'),
11327            'token' => $token,
11328            'ZPaymentFullLogs' => array(
11329                'paymentHash' => isset($paymentHash) ? $paymentHash : "" ,
11330                'money' => $pData['amount'],
11331                'discounted_amount' => (isset($userData['monthlyDiscount']) ? $userData['monthlyDiscount'] : 0),
11332                'monthlyDiscount' => (isset($userData['monthlyDiscount']) ? $userData['monthlyDiscount'] : 0)
11333            ),
11334            'paymentPlanData' => $pData,
11335            'receivablePayment' => $receivablePayment,
11336            'appreciationReceivable' => $appreciationReceivable,
11337            'liveLessonReceivable' => $liveLessonReceivable,
11338            'formType' => $formType
11339        );
11340
11341        if ($annualDiscountOptionData) {
11342            $sessionPaypalParams['annualDiscountOption'] = $annualDiscountOptionData;
11343        }
11344
11345        if (isset($userData['monthlyDiscount']) && isset($userData['monthly_grp_id'])) {
11346            $sessionPaypalParams['monthlyDiscount'] = $userData['monthlyDiscount'];
11347            $sessionPaypalParams['monthly_grp_id'] = $userData['monthly_grp_id'];
11348        }
11349
11350        $this->Session->write('paypalPaymentCreditRetryData', $sessionPaypalParams);
11351        $isZeusUser = isset($userData['card_company']) && $userData['card_company'] == 1 ? true : false;
11352
11353        // ------ End confirmation page ----------
11354
11355        $this->set('token', $token);
11356        $this->set('currencyData', $currencyData);
11357        $this->set('paypalUserData', $userData);
11358        $this->set('userApiToken', $userData['api_token']);
11359        $this->set('isZeusUser', $isZeusUser);
11360
11361        // - NJ-23812 : set view corp
11362        $this->set('monthlyPriceRaw',$monthlyPriceRaw);
11363        $this->set('currencySymbol',$currencyData['symbol']);
11364        $this->set('monthlyPriceSymbol',myTools::getCurrencySymbol($userData['currency_code']));
11365
11366
11367        $this->setSupportPayPal($userData);
11368        $this->set('zeusTransactionFlag', true);
11369        $this->set('paymentHash', $pt['payment_hash']);
11370        $this->set('amount', $pData['amount']);
11371        $this->set('fAmount', $pData['fAmount']);
11372        $this->set('lessonFee', $lessonFee);
11373        $this->set('basicFee', $basicFee);
11374        $this->set('discountedAmount', (isset($userData['discounted_amount']) ? $userData['discounted_amount'] : 0));
11375        $this->set('corporateFlg', $corporateUser);
11376        $this->set('corporateType', $corporateType);
11377        $this->setPaymentViewVars();
11378    }
11379
11380    private function wp_credit_retry() {
11381
11382        // - NJ-23812
11383        if ($this->Session->read('credit_skip_to_confirmation')) {
11384            $this->Session->delete('credit_skip_to_confirmation');
11385        }
11386
11387        // set variables
11388        $userData = $this->sharedUserData['User'];
11389        $apiToken = $userData['api_token'];
11390        $memKey = "pc_wp_retry_card_type_{$apiToken}";
11391        $memData = $this->memcache->get($memKey);
11392        $cardType = isset($memData['cardType']) ? $memData['cardType'] : 0;
11393
11394        // redirect to mypage if empty payment data and payment plan id or price id is null
11395        if (!$pData = $this->getRetryPaymentData($userData, 'card_retry')) {
11396            return $this->redirect('/');
11397        }
11398
11399        if ($this->request->is('post')) {
11400            $cardType = $this->request->data['cardType'];
11401
11402            // memcache card type value
11403            $this->memcacheCardType(array(
11404                'key' => $memKey,
11405                'value' => array('cardType' => $cardType)
11406            ));
11407
11408            // redirect to hosted page if using new card ($cardType = 1)
11409            if ($cardType) {
11410                return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/payment/wp_credit_retry_form");
11411            // redirect to confirm page if using existing card ($cardType = 0)
11412            } else {
11413
11414                // - NJ-23812: write session to skip and auto charge 
11415                $this->Session->write('credit_skip_to_confirmation',true);
11416
11417                return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/payment/payment_credit_retry_confirm");
11418            }
11419        }
11420
11421        /* check if there is error during payment process */
11422        if ($errorType = isset($this->request->query['wpErrType']) ? $this->request->query['wpErrType'] : null) {
11423            if ($error = myTools::getWorldpayErrorMsg($errorType)) {
11424                $this->set('error', $error);
11425            }
11426        } else {
11427            $memErrorKey = 'pc_wp_retry_error_' . $apiToken;
11428            if ($error = $this->memcache->get($memErrorKey)) {
11429                $this->set('error', $error);
11430
11431                // delete memcache error
11432                $this->memcache->delete($memErrorKey);
11433            }
11434        }
11435
11436        // -- start NJ-23812 : skip confirmation page  ------
11437        $formType = Configure::read('payment_credit_retry');
11438        $this->checkUser($formType);
11439
11440        // check if allowed aftee
11441        $this->checkAfteeSupported($this->sharedUserData['User'],true);
11442
11443        $isCardRegistered = (!empty($userData['card_brand']) && !empty($userData['card_number'])) ? true : false;
11444
11445        // - set view variables 
11446        $this->set('pmtValue', 'payment');
11447        $this->set('isCardRegistered',$isCardRegistered);
11448        $this->set('apiToken', $apiToken);
11449        $this->set('logFileName', 'payment_credit_retry');
11450        $this->set('nc_terminal_type', 1); // pc
11451        $this->set('memKeyError', 'pc_wp_retry_error_'.$apiToken);
11452        $this->set('referrer', urlencode(myTools::getUrl(). "/{$this->localizeDir}/payment/payment_credit_retry"));
11453        $this->set('successUrl', urlencode(myTools::getUrl()."/{$this->localizeDir}/payment/payment_credit_retry_complete"));
11454        $this->set('formType', $formType);
11455
11456        // -- end NJ-23812 ----------------------------------
11457
11458        $currencyData = $this->Currency->getSymbolAndPosition($userData['currency_code']);
11459        $this->set('monthlyPrice', $pData['fAmount']);
11460        $this->set('monthlyPriceSymbol',myTools::getCurrencySymbol($userData['currency_code']));
11461
11462        // set view variables
11463        $this->set('cardLogo', myTools::getWorldpayCardLogo($userData['card_brand']));
11464        $this->set('cardType', $cardType);
11465        $this->set('cardBrand', $userData['card_brand']);
11466        $this->set('cardNumber', $userData['card_number']);
11467        $this->render('/Payment/wp_payment_credit_retry');
11468    }
11469    /**
11470     * @api {get} /:language/payment/payment_credit_retry_confirm payment_credit_retry_confirm()
11471     * @apiName payment_credit_retry_confirm
11472     * @apiGroup Payment
11473     * @apiDescription This endpoint is used to process payment credit retry confirmation.
11474     * 
11475     * @apiParam {String} language Language code of the user
11476     * 
11477     * @apiSuccess {View} Redirect redirects to zeus credit retry confirm function for currency is equals to jpy
11478     * @apisuccess {View} Redirect redirects to wp credit retry confirm function is non jpy
11479     * 
11480     * @apiSuccessExample Success Response JPY:
11481     * Redirects to zeus credit retry confirm function
11482     * 
11483     * @apiSuccessExample Success Response Non JPY:
11484     * Redirects to wp credit retry confirm function
11485     * 
11486     * @apiSampleRequest off
11487     */
11488    public function payment_credit_retry_confirm() {
11489        $this->checkUser(Configure::read('payment_credit_retry'));
11490        // redirect to zeus if currency is equals to jpy
11491        if ($this->sharedUserData['User']['currency_code'] == Configure::read('default.user_currency')) {
11492            $this->zeus_credit_retry_confirm();
11493        // redirect to wp
11494        } else {
11495            $this->wp_credit_retry_confirm();
11496        }
11497    }
11498
11499    private function zeus_credit_retry_confirm() {
11500        $data = $this->Session->read('PaymentCreditRetryInfo');
11501        if (!$data) {
11502            return $this->redirect(myTools::getUrl() . '/');
11503        }
11504        $userData = $this->sharedUserData['User'];
11505        $corporateFlg = ( !empty($userData["corporate_id"]) && !empty($userData["payment_plan_id"]) );
11506
11507        $readSkipConfirmation = $this->Session->read('credit_skip_to_confirmation');
11508        if ($readSkipConfirmation) {
11509            $this->Session->delete('credit_skip_to_confirmation');
11510        }
11511
11512        if ($this->request->is('post') || $readSkipConfirmation) {
11513            # check if token matches token in session
11514            $checkToken = $this->checkToken($data['token']);
11515            # check if token is true
11516            if ($checkToken) {
11517                # unset previously set tokens
11518                $this->unsetToken();
11519                $formType = Configure::read('payment_credit_retry');
11520                $referrer = array('controller' => 'Payment', 'action' => 'payment_credit_retry');
11521                $this->z_start($data, $formType, $referrer);
11522            }
11523        }
11524
11525        if (isset($data['ZPaymentFullLogs']['cardnumber']) && !empty($data['ZPaymentFullLogs']['cardnumber'])) {
11526            $cardNumberArr = str_split($data['ZPaymentFullLogs']['cardnumber'], 4);
11527            $this->set('cardNumber', end($cardNumberArr));
11528        } else {
11529            $this->getAndSetCardInfo($this->sharedUserData['User']);
11530        }
11531
11532        $currencyData = $this->Currency->getSymbolAndPosition($userData['currency_code']);
11533        $this->set('currencyData', $currencyData);
11534
11535        $corporateAmount = $this->Session->read('PaymentCreditRetryInfoCorporateAmount') ? $this->Session->read('PaymentCreditRetryInfoCorporateAmount') : null;
11536        $this->set('corporateAmount', $corporateAmount);
11537        $this->set('data', $data);
11538        $this->set('corporateFlg', $corporateFlg);
11539        $this->set('corporateType', myTools::getCoporateTypeUsingPaymentPlanId($userData['payment_plan_id'])); 
11540    }
11541
11542    private function wp_credit_retry_confirm() {
11543        $this->response->disableCache();
11544        // set variables
11545        $logFileName = 'card_retry';
11546        $formType = Configure::read('payment_credit_retry');
11547        $userData = $this->sharedUserData['User'];
11548        $userId = $userData['id'];
11549        $currencyCode = $userData['currency_code'];
11550        $apiToken = $userData['api_token'];
11551
11552        $readSkipConfirmation = $this->Session->read('credit_skip_to_confirmation');
11553        if ($readSkipConfirmation){
11554            $this->Session->delete('credit_skip_to_confirmation');
11555        }
11556
11557        $memKey = "pc_wp_retry_card_type_{$apiToken}";
11558        // redirect to mypage if memcache card type is not set
11559        if (!$this->memcache->get($memKey)) {
11560            return $this->redirect('/');
11561        }
11562
11563        // redirect to retry page if empty payment data and payment plan id or price id is null
11564        if (!$pData = $this->getRetryPaymentData($userData, $logFileName)) {
11565            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed getRetryPaymentData --> ' . json_encode($userData), 'error');
11566            return $this->redirect('/');
11567        }
11568
11569        $apiToken = $userData['api_token'];
11570        $userData['payment_plan_id'] = $pData['paymentPlanId'];
11571        $userData['price_id'] = $pData['priceId'];
11572        $amount = $pData['amount'];
11573
11574        if ($this->request->is('post') || $readSkipConfirmation) {
11575
11576            // NJ-47740
11577            // confiscate pending request coupon for native and callan option
11578            // since student are failed settlement -> native and then callan options are already cancelled
11579            $this->UsersCouponV1->confiscateOptionDiscount(array('userId' => $userId));
11580            $coupon = $this->UsersCouponV1->getCouponUseRequest(array(
11581                'userId' => $userId,
11582                'kbn' => Configure::read('coupon_kbn.monthly_settlement')
11583            ));
11584            
11585            if (
11586                !empty($coupon['result']) && 
11587                !empty($coupon['grp_id']) && 
11588                !empty($coupon['amount']) && 
11589                empty($coupon['has_payment']) // exclude if coupon has payment
11590            ) {
11591                $amount -= $userData['discounted_amount'] = $coupon['amount'];
11592                $userData['monthlyDiscount'] = $coupon['amount'];
11593                $userData['monthly_grp_id'] = $coupon['grp_id'];
11594            }
11595            // NJ-47740 end
11596
11597            $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userId);
11598            $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('appreciation_data.payment_element_type') );
11599            $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.live'));
11600
11601            // add retry payment, receivable payment amount and live lesson payment 
11602            $totalAmount = $amount + $receivablePayment + $appreciationReceivable + $liveLessonReceivable;
11603            $orderCode = myTools::generateOrderCode($userId);
11604
11605            $paymentMethodType = myTools::getWPPaymentMethodType($userData['card_brand'], 'payment');
11606            $merchantCode = myTools::getWPMerchantCode($paymentMethodType);
11607            $paymentMethod = explode('_', $paymentMethodType);
11608            $paymentMethod = isset($paymentMethod[0]) ? $paymentMethod[0] : null;
11609            $currencyExponents = Configure::read('worldpay.currency_exponents');
11610            $exponent = $currencyExponents[$currencyCode];
11611
11612            // get total amount with checking currency exponent
11613            $totalAmountArr = myTools::wpGetAmount($exponent, $totalAmount);
11614            $ncAmount = $totalAmountArr['ncAmount'];
11615            $wpAmount = $totalAmountArr['wpAmount'];
11616
11617            $wpData = array(
11618                'cardToken' => $userData['card_token'],
11619                'merchantCode' => $merchantCode,
11620                'paymentHash' => $orderCode,
11621                'wpPaymentAmount' => $wpAmount
11622            );
11623
11624            // set payment amount
11625            $userData['paymentAmount'] = $ncAmount;
11626
11627            // create payment transaction
11628            if (!$pt = $this->createPaymentTransaction($formType, $userData, $wpData)) {
11629                $this->log(__METHOD__ .' Failed to save payment transaction. Params --> ' . json_encode($wpData), $logFileName);
11630                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to save payment transaction. Params --> ' . json_encode($wpData), 'error');
11631                return $this->redirect('/');
11632            }
11633
11634            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - After save payment transaction. Params --> ' . json_encode($wpData), 'error');
11635
11636            // if aftee payment
11637            if ($userData['card_company'] == Configure::read('card_company.aftee') ) {
11638
11639                // default result
11640                $checkRes = array(
11641                    'OrderCode' => $orderCode,
11642                    'authentication_token' => $userData['card_token'],
11643                    'response' => 'Aftee payment amount is zero',
11644                    'customer' => array(
11645                        'phone_number' =>  $userData['phone_number']
11646                    )
11647                );
11648                $receivableResult = json_encode($checkRes);
11649                $afteeTransactionIdentifier = $userData['aftee_transaction_identifier'];
11650
11651
11652                if ($userData['paymentAmount'] > 0) {
11653
11654                    if (!class_exists('AfteePaymentService')) {
11655                        App::uses('AfteePaymentService','Lib');
11656                    }
11657                    $afteeService = new AfteePaymentService();
11658                    $afteeChecksumData = array(
11659                        'shopItemId' => "AFTEE" . $formType,
11660                        'itemName' => 'CreditRetryUsingExistingCard',
11661                        'itemPrice' => $userData['paymentAmount'],
11662                        'itemCount' => 1,
11663                        'customerPhoneNumber' => $userData['phone_number'],
11664                        'customerEmail' => $userData['email'],
11665                        'shopTransactionNo' => $orderCode,
11666                        'userID' =>  $userData['id']
11667                    );
11668                    $checksum = $afteeService->generateChecksum($afteeChecksumData, false);
11669                    $afteeData = array(
11670                        'authentication_token' => $userData['card_token'],
11671                        'related_id' => $userData['aftee_transaction_identifier'],
11672                        'checksum' => $checksum['checksum'],
11673                        'shop_transaction_no' => $orderCode,
11674                        'transaction_options' => array(1)
11675                    );
11676            
11677                    $afteePaymentData = array_merge($afteeData, $checksum['settlementData']);
11678        
11679                    // aftee execute payment
11680                    $receivableResult = $afteeService->directPayment($afteePaymentData);
11681                    $checkRes = json_decode($receivableResult, true);
11682
11683
11684                    if ( isset($checkRes['object']) && $checkRes['object'] == 'transaction') {
11685                        $prPaymentSuccess = true;
11686                    } else if ( !array_key_exists("object", $checkRes) || (isset($checkRes['object']) && $checkRes['object'] == 'error')) {
11687                        $prPaymentSuccess = false;
11688                    }
11689
11690                    $afteeTransactionIdentifier = isset($checkRes['id']) && !empty($checkRes['id']) ? $checkRes['id'] : NULL;
11691                    if (isset($checkRes['related_transaction']) && !empty($checkRes['related_transaction'])) {
11692                        $afteeTransactionIdentifier = $checkRes['related_transaction'];
11693                    }
11694                    $orderCode = isset($checkRes['shop_transaction_no']) && !empty($checkRes['shop_transaction_no']) ? $checkRes['shop_transaction_no'] : NULL;
11695                    $checkRes['OrderCode'] = $orderCode;
11696                }
11697
11698                // process payment data
11699                if ($prPaymentSuccess || $userData['paymentAmount'] == 0) {
11700                    // set user model
11701                    $uModel = $this->User;
11702                    $dataSource = $uModel->getDataSource();
11703                    $dataSource->begin();
11704
11705                    $afteeParams = array(
11706                        'data' => $checkRes,
11707                        'ptData' => $pt,
11708                        'logFileName' => $logFileName,
11709                        'dataSource' => $dataSource,
11710                        'amount' => $userData['paymentAmount'],
11711                        'userData' => $userData,
11712                        'transactionIdentifier' => $afteeTransactionIdentifier,
11713                        'aftee' => 1
11714                    );
11715    
11716                    $this->processAfteePayment($afteeParams);
11717                }
11718
11719                // update payment transaction
11720                $updateData = array(
11721                    'id' => $pt['id'],
11722                    'fields' => array(
11723                        'status' => $prPaymentSuccess,
11724                        'response_text' => array('aftee_directPayment_response' => $receivableResult))
11725                );
11726
11727                // update payment transaction
11728                $this->PaymentTransaction->updateAfteePaymentTransaction($updateData);
11729
11730
11731                // redirect to payment_credit_charge with error display if direct payment response is not authorised
11732                if (!$prPaymentSuccess && $userData['paymentAmount'] > 0) {
11733                    if (!class_exists('myMemcached')) {
11734                        App::uses('myMemcached', 'Lib');
11735                    }
11736                    $memKeyError = 'pc_wp_retry_error_' . $apiToken;
11737                    $memerror = __('トランザクションを完了できません。 もう一度お試しください。');
11738                    $memcached = new myMemcached();
11739                    $memcached->set(array(
11740                        'key' => $memKeyError,
11741                        'value' => $memerror,
11742                        'expire' => 3600 // 1 hour
11743                    ));
11744                    return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/payment/payment_credit_retry");
11745                }
11746
11747            } else {
11748
11749                $wpData = array(
11750                    'merchantCode' => $merchantCode,
11751                    'orderCode' => $orderCode,
11752                    'description' => 'Credit Retry Using Existing Card',
11753                    'currencyCode' => $currencyCode,
11754                    'exponent' => $exponent,
11755                    'amount' => $wpAmount,
11756                    'cardToken' => $userData['card_token'],
11757                    'email' => $userData['email'],
11758                    'authenticatedShopperId' => $userId,
11759                    'xmlName' => 'direct_payment_with_token',
11760                    'shopperIpAddress' => $_SERVER["REMOTE_ADDR"],
11761                    'wpTransactionIdentifier' => $userData['wp_transaction_identifier'],
11762                    'paymentMethod' => $paymentMethod
11763                );
11764
11765                $result = wpPaymentService::directPayment($wpData);
11766
11767                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - directPayment result --> ' . json_encode($result), 'error');
11768
11769                $updateData = array(
11770                    'id' => $pt['id'],
11771                    'fields' => array('response_text' => array('directPayment_response' => $result)),
11772                    'logFileName' => $logFileName
11773                );
11774
11775                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - before updatePaymentTransaction result --> ' . json_encode($updateData), 'error');
11776                
11777                // update payment transaction direct response
11778                $this->updatePaymentTransaction($updateData);
11779
11780                // redirect to payment credit retry with error display if direct payment response is not authorised
11781                if (!myTools::checkIfWPPaymentResponseIsAuthorised($result)) {
11782                    $params = array(
11783                        'apiToken' => $apiToken,
11784                        'wpResponse' => $result,
11785                        'memKey' => 'pc_wp_retry_error_' . $apiToken
11786                    );
11787                    myTools::parseAndSetWPErrorResponse($params);
11788                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - WP Payment not authorised --> ' . json_encode($params), 'error');
11789                    return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/payment/payment_credit_retry");
11790                }
11791
11792                // - flag manual paying user success
11793                UserTable::saveManualPayingUsersToMemcache($userId);
11794            }
11795
11796
11797            // delete memcache
11798            if ($this->memcache->get($memKey)) {
11799                $this->memcache->delete($memKey);
11800            }
11801            return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/payment/payment_credit_retry_complete");
11802        }
11803
11804        $currencyData = $this->Currency->getSymbolAndPosition($currencyCode);
11805        $this->set('monthlyPrice', myTools::addPriceSymbol($pData['fAmount'], $currencyData['symbol'], $currencyData['prefix_suffix_flg']));
11806
11807        // set view variables
11808        $this->set('cardLogo', myTools::getWorldpayCardLogo($userData['card_brand']));
11809        $this->set('cardBrand', $userData['card_brand']);
11810        $this->set('cardNumber', $userData['card_number']);
11811        $this->set('cardCompany', $userData['card_company']);
11812        $this->render('/Payment/wp_payment_credit_retry_confirm');
11813    }
11814    /**
11815     * @api {get} /:language/payment/paypal_payment_credit_retry_confirm paypal_payment_credit_retry_confirm()
11816     * @apiName paypal_payment_credit_retry_confirm
11817     * @apiGroup Payment
11818     * @apiDescription This endpoint is used to display the paypal payment credit retry confirm form.
11819     * 
11820     * @apiParam {String} language Language code of the user
11821     * 
11822     * @apiSuccess {View} Render Displays the paypal payment credit retry confirm form
11823     * 
11824     * @apiError {View} Redirect Redirects to mypage if missing paypal payment credit retry data
11825     * 
11826     * @apiSuccessExample Success Response:
11827     * Displays the paypal payment credit retry confirm form
11828     * 
11829     * @apiErrorExample Error Response:
11830     * Redirects to mypage if missing paypal payment credit retry data
11831     * 
11832     * @apiSampleRequest off
11833     */
11834    public function paypal_payment_credit_retry_confirm() {
11835        $logFileName = 'paypal_debug';
11836        $user = $this->sharedUserData['User'];
11837
11838        $data = $this->Session->read('paypalPaymentCreditRetryData');
11839        if (!$data) {
11840            $this->log(__METHOD__ . ' Missing paypal payment credit retry data. --> ' . json_encode($data) . ' | user id  --> ' . json_encode($user['id']), $logFileName);
11841            return $this->redirect(myTools::getUrl());
11842        }
11843
11844        // set payment gateway type
11845        $this->memcache->set(array(
11846            'key' => 'creditRetryPaymentGatewayType_' . $user['api_token'],
11847            'value' => $data['payment_gateway_type'],
11848            'expire' => 3600 // 1 hour
11849        ));
11850
11851        $currencyData = $this->Currency->getSymbolAndPosition($user['currency_code']);
11852        $this->set('currencyData', $currencyData);
11853        $this->set('fAmount', myTools::formatAmount($data['ZPaymentFullLogs']['money']));
11854        $this->set('paypalUserData', $user);
11855        $this->set('userApiToken', $user['api_token']);
11856    }
11857    /**
11858     * @api {get} /:language/payment/wp_credit_retry_form wp_credit_retry_form()
11859     * @apiName wp_credit_retry_form
11860     * @apiGroup Payment
11861     * @apiDescription This endpoint is used to display the credit retry form for wp.
11862     * 
11863     * @apiParam {String} language Language code of the user
11864     * 
11865     * @apiSuccess {View} Render Displays the wp credit retry form
11866     * 
11867     * @apiError {View} Redirect Redirects to mypage if memcache card type is not set
11868     * 
11869     * @apiSuccessExample Success Response:
11870     * Displays the wp credit retry form
11871     * 
11872     * @apiErrorExample Error Response:
11873     * Redirects to mypage if memcache card type is not set
11874     * 
11875     * @apiSampleRequest off
11876     */
11877    public function wp_credit_retry_form() {
11878        $this->response->disableCache();
11879        $formType = Configure::read('payment_credit_retry');
11880        $this->checkUser($formType);
11881        $apiToken = $this->sharedUserData['User']['api_token'];
11882
11883        $memKey = "pc_wp_retry_card_type_{$apiToken}";
11884        // redirect to mypage if memcache card type is not set
11885        if (!$this->memcache->get($memKey)) {
11886            return $this->redirect('/');
11887        }
11888
11889        $enableAftee = (isset($this->localizeDir) && $this->localizeDir == 'zh-tw') ? 1 : 0;
11890        if (isset($this->sharedUserData['User']['currency_code']) && $this->sharedUserData['User']['currency_code'] != 'TWD') {
11891            $enableAftee = 0;
11892        }
11893        $this->set('enableAftee', false);
11894
11895        // set view vars
11896        $this->set('pmtValue', 'payment');
11897        $this->set('apiToken', $apiToken);
11898        $this->set('logFileName', 'payment_credit_retry');
11899        $this->set('nc_terminal_type', 1); // pc
11900        $this->set('memKeyError', 'pc_wp_retry_error_'.$apiToken);
11901        $this->set('referrer', urlencode(myTools::getUrl(). "/{$this->localizeDir}/payment/payment_credit_retry"));
11902        $this->set('successUrl', urlencode(myTools::getUrl()."/{$this->localizeDir}/payment/payment_credit_retry_complete"));
11903        $this->set('formType', $formType);
11904    }
11905    /**
11906     * @api {get} /:language/payment/paypal_payment_credit_retry_process/:token/:negativeTesting paypal_payment_credit_retry_process()
11907     * @apiName paypal_payment_credit_retry_process
11908     * @apiGroup Payment
11909     * @apiDescription This endpoint is used to process the paypal payment credit retry.
11910     * 
11911     * @apiParam {String} language Language code of the user
11912     * @apiParam {String} token Token of the user
11913     * @apiParam {Number} negativeTesting Negative testing flag 1 for true, 0 for false
11914     * 
11915     * @apiSuccess {View} Redirect Redirects to {{ENV}}/payment/payment_credit_retry_complete if payment is successful
11916     * 
11917     * @apiError {View} Redirect Redirects to {{ENV}}/payment/payment_credit_retry if payment is unsuccessful
11918     * 
11919     * @apiSuccessExample Success Response:
11920     * Redirects to {{ENV}}/payment/payment_credit_retry_complete
11921     * 
11922     * @apiErrorExample Error Response:
11923     * Redirects to {{ENV}}/payment/payment_credit_retry
11924     * 
11925     * @apiSampleRequest off
11926      */
11927    public function paypal_payment_credit_retry_process() {
11928        $this->autoRender = false;
11929        $this->layout = false;
11930
11931        $logFileName = 'paypal_debug';
11932        $user = $this->sharedUserData['User'];
11933        $userId = $user['id'];
11934        $get = $this->request->query;
11935
11936        $data = $this->Session->read('paypalPaymentCreditRetryData');
11937
11938        if (!$data) {
11939            $this->log(__METHOD__ . ' Missing paypal payment credit retry data. --> ' . json_encode($data) . ' | user id  --> ' . json_encode($userId), $logFileName);
11940            return json_encode($res);
11941        }
11942
11943        if ((isset($get['negativeTesting']) && $get['negativeTesting']) || !$this->processPayPalPayment($data, $user)) {
11944            $this->Session->setFlash('決済失敗', array("element" => "flashfail"));
11945
11946            $memKey = 'paypalBillingAgreementData_' . $get['token'];
11947
11948            // delete memcache billing agreement data
11949            if ($this->memcache->get($memKey)) {
11950                $this->memcache->delete($memKey);
11951            }
11952
11953            return $this->redirect(myTools::getUrl('payment/payment_credit_retry'));
11954        }
11955
11956        $memKey = 'creditRetryPaymentGatewayType_' . $this->sharedUserData['User']['api_token'];
11957        // delete memcache
11958        if ($this->memcache->get($memKey)) {
11959            $this->memcache->delete($memKey);
11960        }
11961
11962        // delete session
11963        $this->Session->delete('paypalPaymentCreditRetryData');
11964
11965        // redirect to payment retry complete
11966        return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_retry_complete'));
11967    }
11968
11969    /**
11970     * @api {get} /payment/checkUser/:type/:referer/:return_membershiptype checkUser()
11971     * @apiName checkUser
11972     * @apiGroup Payment
11973     * @apiDescription This endpoint is used to check the user.
11974     * 
11975     * @apiParam {String} type Type of the user. Null by default
11976     * @apiParam {String} referer Referer of the user. Null by default
11977     * @apiParam {Boolean} return_membershiptype Return membership type of the user. False by default
11978     * 
11979     * @apiSuccess {String} memberType Returns the membership type of the user if return_membershiptype is true
11980     * @apiSuccess {View} Redirect Redirects to appropriate page
11981     * 
11982     * @apiSuccessExample Success Response Return Membership Type:
11983     * paid_user
11984     * 
11985     * @apiSuccessExample Success Response Redirect to Error Page:
11986     * Redirects to {{ENV}}/account/retry/error
11987     * 
11988     * @apiSuccessExample Success Response Redirect to Home Page:
11989     * Redirects to {{ENV}}/
11990     * 
11991     * @apiSuccessExample Success Response Redirect to Payment Credit Change Pass:
11992     * Redirects to {{ENV}}/payment/payment_credit_change
11993     * 
11994     * @apiSuccessExample Success Response Redirect to Payment Credit Register:
11995     * Redirects to {{ENV}}/payment/payment_credit_register
11996     * 
11997     * @apiSuccessExample Success Response Redirect to Payment Credit Retry:
11998     * Redirects to {{ENV}}/payment/payment_credit_retry
11999     * 
12000     * @apiSuccessExample Success Response Default:
12001     * true
12002     * 
12003     * @apiSampleRequest off
12004     */
12005    public function checkUser($type = null, $referer = null, $return_membershiptype = false) {
12006        $user = new UserTable($this->sharedUserData['User']);
12007        $memberType = $user->getUserMembership();
12008
12009        if($return_membershiptype) {
12010            return $memberType;
12011        }
12012
12013        // redirect to error page if settlement cron is currently on-going
12014        if (UserTable::checkPayingUser($user->id)) {
12015            return $this->redirect(myTools::getUrl() . '/account/retry/error');
12016        }
12017
12018        // NJ-25522: since payment has been made after 3D Secure challenge, membership of user is now updated
12019        // bypass membership checking; continue for cards without 3D Secure challenge
12020        $zeus3DSecureChallengeFlg = $this->memcache->get('zeus3DSecureChallengeFlg_' . $user->id);
12021        if ($zeus3DSecureChallengeFlg) {
12022            return true;
12023        }
12024
12025
12026        # if page is from retry
12027        if ($type == Configure::read('payment_credit_retry')) {
12028            if ($memberType == Configure::read('user.member_type_paid')) {
12029                return $this->redirect(myTools::getUrl() . '/');
12030            }
12031        }
12032
12033        # if page is from change
12034        if ($type == Configure::read('payment_credit_change')) {
12035            # get query
12036            $testQuery = $this->request->query;
12037            $currTime = (int) date("d");
12038
12039            # check test date now
12040            if (isset($testQuery["testDateNow"])) {
12041                $currTime = (int) date("d", strtotime($testQuery["testDateNow"]));
12042            }
12043
12044            # check if user is with telecom, and the current time is 1st day of month || time between 00:00:00 and 10:00:00
12045            if (
12046                $user->card_company == Configure::read("card_company.telecom")
12047                && $currTime === 1
12048            ) {
12049                # set the flash message
12050                # $this->Session->setFlash("Error : 本日は決済日のため、コイン購入およびカード情報変更を停止しております。 恐れ入りますが、手続きは明日以降にてお願い致します。", array("element" => "flashfail"));
12051                return $this->redirect(
12052                    array(
12053                        "controller" => "payment",
12054                        "action" => "payment_credit_change",
12055                        "?" => array(
12056                            "disabled" => 1
12057                        )
12058                    )
12059                );
12060            }
12061
12062            # if user is free
12063            if ($memberType == Configure::read('user.member_type_free')) {
12064                return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_register'));
12065            }
12066            # if user is a fail user
12067            if ($memberType == Configure::read('user.member_type_fail')) {
12068                return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_retry'));
12069            }
12070        }
12071
12072        # if page is from charge
12073        if ($type == Configure::read('payment_credit_force_charge')) {
12074            //NJ-3882 If User is Free (Trial not yet conducted)
12075            $membershipTypeIndex = $user->getMembershipTypeIndex();
12076            // allow corporate individual since it has no free trial
12077            if ($membershipTypeIndex == 13 && empty($user->corporate_id) && myTools::isDateEmpty($user->first_charge_date)) {
12078                return $this->redirect(myTools::getUrl() . '/');
12079            }
12080            
12081            if ($memberType == Configure::read('user.member_type_paid') && $user->payment_plan_id != Configure::read('payment_plans.complimentary_plan')) {
12082                return $this->redirect(myTools::getUrl() . '/');
12083            }
12084            // if user is free trial again, Corporate users has no free trial
12085            if ($memberType == Configure::read('user.member_type_free') && $user->double_check_flg == 1 && empty($user->corporate_id) && myTools::isDateEmpty($user->first_charge_date)) {
12086                return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_register'));
12087            }
12088
12089            // if failed user
12090            if ($memberType == Configure::read('user.member_type_fail')) {
12091                return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_retry'));
12092            }
12093        }
12094
12095        # if page is from register
12096        if ($type == Configure::read('payment_credit_authentication') && !$user->complimentary_code) {
12097            $membershipTypeIndex = $user->getMembershipTypeIndex();
12098            # if user is paid
12099            if ($memberType == Configure::read('user.member_type_paid')) {
12100                return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_change'));
12101            }
12102            # if user is a fail user
12103            if ($memberType == Configure::read('user.member_type_fail')) {
12104                return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_retry'));
12105            }
12106            # If user is free
12107            if ($membershipTypeIndex == 12) {
12108                return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_charge'));
12109            }
12110        }
12111
12112        # return true by default
12113        return true;
12114    }
12115
12116    /**
12117     * validate form data
12118     * @param  [type] $data [description]
12119     * @return status of form validity
12120     */
12121    public function formDataValidation($data) {
12122        $err = array();
12123        $year = (int)date('y');
12124        $valid = array('3','4','5','6');
12125        $form = 'ZPaymentFullLogs';
12126
12127        // NC-3914: if paymnent type is either retry | charge and user didn't use new card.
12128        if (isset($data[$form]['credit_confirm']) && !$data[$form]['credit_confirm']) {
12129            return array('err' => false);
12130        }
12131
12132        // NC-2961: return error false if zeus card option exist
12133        if (isset($data[$form]['zeus_card_option'])) {
12134            return array('err' => false);
12135        }
12136        
12137        if (!isset($data[$form]['clientip'])) {
12138            unset($data[$form]['clientip']);
12139            $err[] = $form."ClientIp";
12140        }
12141
12142        if (isset($data[$form]['cardnumber']) && preg_match("/[^0-9]/", $data[$form]['cardnumber']) != 1) {
12143            if ( (strlen($data[$form]['cardnumber']) >= 14 && strlen($data[$form]['cardnumber']) <= 16) == false || !in_array($data[$form]['cardnumber'][0], $valid) ) {
12144                unset($data[$form]['cardnumber']);
12145                $err[] = $form."Cardnumber";
12146            }
12147        }
12148
12149        if (isset($data[$form]['expyy']) && preg_match("/[^0-9]/", $data[$form]['expyy']) != 1 && !((int)$data[$form]['expyy'] >= $year && (int)$data[$form]['expyy'] <= $year+20)) {
12150            unset($data[$form]['expyy']);
12151            $err[] = $form."ExpirationDate";
12152        }
12153
12154        if (isset($data[$form]['expmm']) && preg_match("/[^0-9]/", $data[$form]['expmm']) != 1 && !((int)$data[$form]['expmm'] >= 1 && (int)$data[$form]['expmm'] <= 12)) {
12155            unset($data[$form]['expmm']);
12156            $err[] = $form."ExpirationDate";
12157        }
12158
12159        if (isset($data[$form]['username']) && preg_match("/^[a-zA-Z ]/", $data[$form]['username']) != 1 && $data[$form]['username']) {
12160            unset($data[$form]['username']);
12161            $err[] = $form."Username";
12162        }
12163
12164        if (isset($data[$form]['telno']) && preg_match("/[^0-9]/", $data[$form]['telno']) != 1 && strlen($data[$form]['telno']) < 10) {
12165            unset($data[$form]['telno']);
12166            $err[] = $form."Telno";
12167        }
12168
12169        if (count($err) == 0) {
12170            return array('err' => false);
12171        } else {
12172            return array('err' => $err, 'data' => $data);
12173        }
12174    }
12175
12176    /**
12177     * withdraw from telecom or zeus
12178     * @param  [type] $user_id [description]
12179     * @return [type]          [description]
12180     */
12181    public function withdraw($user_id = null) {
12182        $response = "NG";
12183
12184        // check if user id exists
12185        if (!$user_id) {
12186            return $response;
12187        }
12188
12189        // get user by id
12190        $user = $this->User->findById($user_id);
12191
12192        // check if user exists
12193        if (!$user) {
12194            return $response;
12195        }
12196
12197        // check card affiliation
12198        if ($user['User']['card_company'] != NULL) {
12199            if ($user['User']['card_company'] == Configure::read('card_company.telecom')) {
12200                    return "OK";
12201            } else if ($user['User']['card_company'] == Configure::read('card_company.zeus')) {
12202                $clientip = $user['User']['card_company'];
12203            }
12204        } else {
12205            return $response;
12206        }
12207
12208        // zpayment get succeeded
12209        $zpayment = $this->ZPaymentSucceeded->find('first',array(
12210                'recursive' => -1,
12211                'conditions' => array(
12212                        'ZPaymentSucceeded.user_id' => $user['User']['id'],
12213                        'ZPaymentSucceeded.clientip' => $clientip,
12214                        // 'ZPaymentSucceeded.created >=' => date('Y-m-d', strtotime('-1 month'.date('Y-m-d'))), //CONFIRM: add condition to select only transactions within the month?
12215                        'LOWER(ZPaymentSucceeded.result)' => "ok"
12216                    ),
12217                'order' => array('ZPaymentSucceeded.created' => 'DESC')
12218            )
12219        );
12220
12221        // check if user has zpayment
12222        if (!$zpayment) {
12223            $data['user_id'] = $user['User']['id'];
12224            $data['error_code'] = Configure::read('zeus.error.no_transaction_record');
12225            $this->_error_log_set($data);
12226            echo "No Transaction Record";
12227            return $response;
12228        }
12229
12230        // withdraw ang get the result
12231        $result = $this->ZCharge->cancel(
12232            $clientip,
12233            $zpayment['ZPaymentSucceeded']['ordd']
12234        );
12235
12236        // check if result is false
12237        if ($result === FALSE) {
12238            echo "Invalid Withdrawal";
12239            exit;
12240        }
12241
12242        if (preg_match('/SuccessOK/', $result) == 1) {
12243            return $response = "OK";
12244        } else if (preg_match('/failure_order/', $result) == 1) {
12245            return $response;
12246        } else if (preg_match('/Invalid/', $result) == 1) {
12247            return $response;
12248        } else if (preg_match('/maintenance/', $result) == 1) {
12249            return $response;
12250        } else if (preg_match('/connect error/', $result) == 1) {
12251            return $response;
12252        }
12253    }
12254
12255    /**
12256     * @api {post} /payment/withdraw_confirm withdraw_confirm()
12257     * @apiName withdraw_confirm
12258     * @apiGroup Payment
12259     * @apiDescription This endpoint is used to confirm the withdrawal.
12260     * 
12261     * @apiBody {Number} card_company Card company of the user
12262     * 
12263     * @apiSuccess {PHP} Set sets the selected card company, current card company, user id and referer for view
12264     * 
12265     * @apiError {View} Redirect Redirects to payment_credit_change if request is not post
12266     * 
12267     * @apiExample {json} Example usage:
12268     * {
12269     *         "card_company": 1
12270     * }
12271     * @apiSuccessExample Success Response:
12272     * Sets the selected card company, current card company, user id and referer for view
12273     * 
12274     * @apiErrorExample Error Response:
12275     * Redirects to payment_credit_change if request is not post
12276     * 
12277     * @apiSampleRequest off
12278     */
12279    public function withdraw_confirm() {
12280        $this->checkUser(Configure::read('payment_credit_change'));
12281        if ($this->request->is('post')) {
12282            $data = $this->request->data;
12283            $user = $this->User->findById($this->Auth->user('id'));
12284            $this->set('selected_card_company', $data['card_company']);
12285            $this->set('current_card_company', $user['User']['card_company']);
12286            $this->set('user_id', $user['User']['id']);
12287            $this->set('referer', $this->referer());
12288        } else {
12289            return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_change'));
12290        }
12291    }
12292
12293    /**
12294     * @api {get} /payment/checkToken/:token checkToken()
12295     * @apiName checkToken
12296     * @apiGroup Payment
12297     * @apiDescription This endpoint is used to check the token.
12298     * 
12299     * @apiParam {String} token Token of the user
12300     * 
12301     * @apiSuccess {Boolean} true returns true if token is valid
12302     * 
12303     * @apiError {View} Redirect Redirects to mypage if token is invalid
12304     * 
12305     * @apiSuccessExample Success Response:
12306     * true
12307     * 
12308     * @apiErrorExample Error Response:
12309     * Redirects to mypage if token is invalid
12310     * 
12311     * @apiSampleRequest off
12312     */
12313    public function checkToken($token = null){
12314        //get session token
12315        $sessionToken = isset($_SESSION['Payment']['token']) ? $_SESSION['Payment']['token'] : '';
12316
12317        if ($token == $sessionToken) {
12318            return true;
12319        } else {
12320            $this->redirect(myTools::getUrl() . '/');
12321        }
12322    }
12323
12324    /**
12325     * @api {post} /payment/unsetToken unsetToken()
12326     * @apiName unsetToken
12327     * @apiGroup Payment
12328     * @apiDescription This endpoint is used to unset the token.
12329     * 
12330     * @apiSuccess {PHP} unset unsets the token
12331     *
12332     * @apiSuccessExample Success Response:
12333     * unsets the token
12334     * 
12335     * @apiSampleRequest off 
12336     */
12337    public function unsetToken() {
12338        if (isset($_SESSION['Payment']['token'])) {
12339            unset($_SESSION['Payment']['token']);
12340        }
12341        return;
12342    }
12343
12344    /**
12345     * Create payment transaction
12346     */
12347    private function createPaymentTransaction($formType = null, $userData = array(), $wpData = array()) {
12348        $pt = array();
12349
12350        if (!$userData) {
12351            $userData = isset($this->sharedUserData['User']) ? $this->sharedUserData['User'] : null;
12352            if (!$userData) {
12353                return $pt;
12354            }
12355        }
12356
12357        if (!$formType) {
12358            return $pt;
12359        }
12360
12361        switch ($formType) {
12362            case Configure::read('payment_credit_retry'):
12363            case Configure::read('payment_credit_chocotto_retry'):
12364                $logFileName = 'card_retry';
12365                break;
12366            case Configure::read('payment_credit_authentication'):
12367            case Configure::read('payment_lite_credit_free'):
12368            case Configure::read('payment_credit_chocotto_free'):
12369                $logFileName = 'card_registration';
12370                break;
12371            case Configure::read('corporate_credit_card_registration'):
12372                $logFileName = 'corporate_credit_card_registration';
12373                break;
12374            case Configure::read('payment_credit_force_charge'):
12375            case Configure::read('payment_prepaid_corporate_light_member'):
12376            case Configure::read('payment_individual_corporate_premium'):
12377            case Configure::read('payment_individual_corporate_standard'):
12378            case Configure::read('payment_lite_credit_paid'):
12379            case Configure::read('payment_credit_chocotto_force_charge'):
12380                $logFileName = 'card_charge';
12381                break;
12382            case Configure::read('payment_credit_change'):
12383                $logFileName = 'card_change';
12384                break;
12385            default:
12386                $logFileName = 'debug';
12387        }
12388
12389        $corporateUser = (isset($userData['corporate_id']) && !empty($userData['corporate_id']));
12390        if (!$corporateUser) {
12391            if (!isset($userData['payment_plan_id'])) {
12392                $this->log(__METHOD__ . ' missing parameter payment plan id. ' . json_encode($userData), $logFileName);
12393                return $pt;
12394            }
12395
12396            if (!isset($userData['price_id'])) {
12397                $this->log(__METHOD__ . ' missing parameter price id. ' . json_encode($userData), $logFileName);
12398                return $pt;
12399            }
12400        }
12401
12402        // change form type if corporate user
12403        if ($corporateUser && $formType == Configure::read('payment_credit_retry')) {
12404            $corpType = myTools::getCoporateTypeUsingPaymentPlanId($userData['payment_plan_id']);
12405            // light
12406            if ($corpType == Configure::read('corporate_type.light')) {
12407                $formType = Configure::read('payment_prepaid_corporate_light_member');
12408            // premium
12409            } elseif ($corpType == Configure::read('corporate_type.premium')) {
12410                $formType = Configure::read('payment_individual_corporate_premium');
12411            // standard
12412            } elseif ($corpType == Configure::read('corporate_type.standard')) {
12413                $formType = Configure::read('payment_individual_corporate_standard');
12414            }
12415        }
12416
12417        // change form type if lite plan user
12418        $litePlanUser = (in_array($userData['payment_plan_id'], Configure::read('lite_payment_plans'))) ? true : false;
12419
12420        if (
12421            $litePlanUser &&
12422            !in_array($formType, array(Configure::read('payment_credit_change'),Configure::read('payment_credit_retry') ) ) &&
12423            !isset($userData['discountOption'])
12424        ) {
12425            $formType = myTools::getLitePlanUserFormType($userData['payment_plan_id']);
12426        }
12427
12428        // change form type if chocotto plan user
12429        $chocottoPlanUser = in_array(
12430            $userData['payment_plan_id'], 
12431            [
12432                Configure::read('payment_plans.free_trial_chocotto'),
12433                Configure::read('payment_plans.chocotto_plan')
12434            ]
12435        );
12436
12437        if (
12438            $chocottoPlanUser &&
12439            !in_array(
12440                $formType,
12441                array(
12442                    Configure::read('payment_credit_chocotto_retry'),
12443                    Configure::read('payment_credit_chocotto_force_charge'),
12444                    Configure::read('payment_credit_change')
12445                )
12446            )
12447        ) {
12448            $formType = myTools::getChocottoPlanUserFormType($userData['payment_plan_id']);
12449        }
12450
12451        // get payment hash
12452        $paymentHash = myTools::generateOrderCode($userData['id']);
12453
12454        // set payment params
12455        $paymentParams = array(
12456            'currencyCode' => $userData['currency_code'],
12457            'paymentPlanId' => $userData['payment_plan_id'],
12458            'priceId' => $userData['price_id'],
12459            'remoteAddress' => $_SERVER["REMOTE_ADDR"],
12460            'formType' => $formType,
12461            'paymentType' => Configure::read('payment_types.payment_plan'),
12462            'paymentAmount' => $userData['paymentAmount'],
12463            'logFileName' => $logFileName
12464        );
12465
12466        if (isset($userData['discountOption'])) {
12467            $paymentParams['discountOption'] = $userData['discountOption'];
12468
12469            if (isset($userData['userRegister'])) {
12470                $paymentParams['userRegister'] = $userData['userRegister'];
12471            }
12472        }
12473
12474        // if corporate user
12475        if ($corporateUser) {
12476            if (isset($userData['basic_fee']) && isset($userData['lesson_fee'])) {
12477                $paymentParams["basicFee"] = $userData['basic_fee'];
12478                $paymentParams["lessonFee"] = $userData['lesson_fee'];
12479            }
12480
12481            if (isset($userData['cprAmount']) && isset($userData['cprDiscount'])) {
12482                $paymentParams['addCorporateReceivable'] = array(
12483                    'amount' => $userData['cprAmount'],
12484                    'discount' => $userData['cprDiscount']
12485                );
12486            }
12487
12488            if (isset($userData['updateCorporateReceivable'])) {
12489                $paymentParams["updateCorporateReceivable"] = $userData['updateCorporateReceivable'];
12490            }
12491
12492            if (isset($userData['corporateSettlementType'])) {
12493                $paymentParams["corporateSettlementType"] = $userData['corporateSettlementType'];
12494            }
12495        }
12496
12497        // annual discount option
12498        if (isset($userData['annualDiscountOption'])) {
12499            $paymentParams['discountOption'] = $userData['annualDiscountOption'];
12500        }
12501
12502        // if worldpay payment transaction
12503        if ($wpData) {
12504            $paymentParams['cardToken'] = $wpData['cardToken'];
12505            $paymentParams['merchantCode'] = $wpData['merchantCode'];
12506            $paymentParams['wpPaymentAmount'] = $wpData['wpPaymentAmount'];
12507            $paymentHash = $wpData['paymentHash'];
12508        }
12509
12510        // set updateFirstChargeDate to true if current plan is complimentary
12511        // set memcache
12512        if (
12513            $formType == Configure::read('payment_credit_force_charge') &&
12514            isset($userData['com_plan_user']) && $userData['com_plan_user']
12515        ) {
12516            $paymentParams['updateFirstChargeDate'] = true;
12517            $this->memcache->set(array(
12518                'key' => 'com_plan_user_' . $userData['id'],
12519                'value' => true,
12520                'expire' => 3600 // 1 hour
12521            ));
12522        }
12523
12524        //- get membership type list
12525        $membershipTypes = UserTable::getEngMembershipTypeData();
12526
12527        //- check original membership is pass
12528        if (isset($userData['original_status_index'])) {
12529            $statusBefore = $membershipTypes[$userData['original_status_index']] ?? '';
12530        }
12531
12532        if (
12533            $formType != Configure::read('payment_credit_change') ||
12534            (isset($userData['com_plan_user']) && $userData['com_plan_user'])
12535        ) {
12536            $statusAfter = $membershipTypes[1]; // premium plan paid
12537
12538            /* -- get before status -- */
12539            if (isset($userData['com_plan_user']) && $userData['payment_plan_id'] == Configure::read('payment_plans.complimentary_plan')) {
12540                $statusBefore = $membershipTypes[15]; // complimentary code
12541                $paymentParams['bonusCoinFlg'] = 1;
12542            } elseif ($userData['charge_flg'] == 0) {
12543                // failed settlement
12544                if ($userData['fail_flg'] == 1) {
12545                    $statusBefore = $membershipTypes[5];
12546                // trial again
12547                } elseif ($userData['fail_flg'] == 0 && $userData['double_check_flg'] == 1) {
12548                    $statusBefore = $membershipTypes[13];
12549                    $statusAfter = $membershipTypes[2];
12550                // unsubscribed
12551                } elseif ($userData['fail_flg'] == 0 && $userData['double_check_flg'] == 2) {
12552                    $statusBefore = $membershipTypes[12];
12553                } else {
12554                    $statusBefore = null;
12555                }
12556            }
12557
12558            if ($corporateUser && $formType != Configure::read('payment_credit_force_charge')) {
12559                $statusAfter = myTools::getCorporateUserMembershipStatusName($membershipTypes, $userData['payment_plan_id']);
12560            }
12561
12562            $user = new UserTable($userData);
12563            $membershipTypeIndex = $user->getMembershipTypeIndex();
12564            if ($membershipTypeIndex == 13) {
12565                $statusBefore = $membershipTypes[13];
12566                $paymentParams['userRegister'] = true;
12567                $statusAfter = $membershipTypes[2];
12568            }
12569            
12570            if (isset($statusBefore)) {
12571                // get platform use
12572                $platform = myTools::mobappDetectPlatform();
12573                $paymentParams['platform'] = $platform == Configure::read('platform.splp') ? Configure::read('platform.pclp') : $platform;
12574                $paymentParams['statusBefore'] = $statusBefore;
12575                $paymentParams['statusAfter'] = $statusAfter;        
12576            } else if (isset($userData['statusBefore']) && isset($userData['statusAfter'])) {
12577                // get platform use
12578                $platform = myTools::mobappDetectPlatform();
12579                $paymentParams['platform'] = $platform == Configure::read('platform.splp') ? Configure::read('platform.pclp') : $platform;
12580                $paymentParams['statusBefore'] = $userData['statusBefore'];
12581                $paymentParams['statusAfter'] = $userData['statusAfter'];
12582            }
12583
12584            if ($litePlanUser) {
12585                $_lightPlanFreeMem = Configure::read('membership_type_lightplan_free');
12586                $_lightPlanPaidMem = Configure::read('membership_type_lightplan_paid');
12587                $paymentParams['statusAfter'] = ($formType == Configure::read('payment_lite_credit_free') ) ? $membershipTypes[$_lightPlanFreeMem] : $membershipTypes[$_lightPlanPaidMem];
12588            }
12589
12590            //- status after chocotto camp
12591            if (in_array($formType, [
12592                Configure::read('payment_credit_chocotto_free'),
12593                Configure::read('payment_credit_chocotto_monthly_payment'),
12594                Configure::read('payment_credit_chocotto_retry'),
12595                Configure::read('payment_credit_chocotto_force_charge')
12596            ])) {
12597                if ($formType == Configure::read('payment_credit_chocotto_free')) {
12598                    $paymentParams['statusAfter'] = $membershipTypes[Configure::read('membership_type_chocotto_plan_free')];
12599                } elseif (in_array(
12600                    $formType, 
12601                    array(
12602                        Configure::read('payment_credit_chocotto_monthly_payment'),
12603                        Configure::read('payment_credit_chocotto_retry'),
12604                        Configure::read('payment_credit_chocotto_force_charge')
12605                    )
12606                )) {
12607                    $paymentParams['statusAfter'] = $membershipTypes[Configure::read('membership_type_chocotto_plan_paid')];
12608                }
12609
12610                $prevPaymentPlanId = (isset($this->mobAppUserData) && !empty($this->mobAppUserData)) ?
12611                    $this->mobAppUserData['User']['payment_plan_id'] :
12612                    ((isset($this->sharedUserData) && $this->sharedUserData) ? $this->sharedUserData['User']['payment_plan_id'] : null);
12613                    
12614                if($prevPaymentPlanId == Configure::read('payment_plans.complimentary_plan')) {
12615                    if(!isset($statusBefore)) {
12616                        $paymentParams['statusBefore'] = $membershipTypes[15];
12617                    }
12618                    if(!isset($platform)) {
12619                        $platform = myTools::mobappDetectPlatform();
12620                        $paymentParams['platform'] = $platform == Configure::read('platform.splp') ? Configure::read('platform.pclp') : $platform;
12621                    }
12622                }
12623            }
12624        }
12625
12626        if (isset($userData['monthlyDiscount']) && isset($userData['monthly_grp_id'])) {
12627            $paymentParams['monthlyDiscount'] = $userData['monthlyDiscount'];
12628            $paymentParams['monthly_grp_id'] = $userData['monthly_grp_id'];
12629        }
12630
12631        if (!empty($userData['couponUseSettlement'])) {
12632            $this->log("LINE ". __LINE__,'card_charge');
12633            $this->log($userData['couponUseSettlement'],'card_charge');
12634            $paymentParams['couponUseSettlement'] = $userData['couponUseSettlement'];
12635        }
12636        //NJ-3882 set UserRegister = true for Free (Trial not yet conducted) user to add 500 bonus coin
12637        $user = new UserTable($userData);
12638        $membershipTypeIndex = $user->getMembershipTypeIndex();
12639
12640        if ($membershipTypeIndex == 13) {
12641            $paymentParams['userRegister'] = true;
12642        }
12643
12644        // - set data
12645        $test = $this->memcache->set(array(
12646            'key' => 'zeus_sec_payment_hash_'.$userData['id'],
12647            'value' => $paymentHash,
12648            'expire' => 600 // 10 minutes
12649        ));
12650
12651
12652        // create payment transaction
12653        $pt = $this->PaymentTransaction->setWPPaymentTransaction(array(
12654            'user_id' => $userData['id'],
12655            'payment_hash' => $paymentHash,
12656            'payment_params' => json_encode($paymentParams),
12657            'course_id' => Configure::read("credit.course_id")
12658        ));
12659
12660        return $pt;
12661    }
12662
12663    /**
12664     * @api {get} /payment/getPaymentTransaction/:userId getPaymentTransaction()
12665     * @apiName getPaymentTransaction
12666     * @apiGroup Payment
12667     * @apiDescription This endpoint is used to get payment transaction.
12668     * 
12669     * @apiParam {String} userId User's ID
12670     * 
12671     * @apiSuccess {PHP} return Returns the payment transation's payment hash
12672     * 
12673     * @apiError {Boolean} false Returns false if no data returned
12674     * 
12675     * @apiSuccessExample Success Response:
12676     * Returns the payment transation's payment hash
12677     * 
12678     * @apiErrorExample Error Response:
12679     * Returns false if no data returned
12680     * 
12681     * @apiSampleRequest off
12682     */
12683    public function getPaymentTransaction($userId = null) {
12684        $data = $this->PaymentTransaction->getPaymentTransaction($userId);
12685        if ($data) {
12686            return isset($data['payment_hash'])? $data['payment_hash'] : null;
12687        }
12688        return false;
12689    }
12690    /**
12691     * @api {get} /mobapp/payment/credit_register_receivable/:token mobapp_payment_credit_register_receivable()
12692     * @apiName mobapp_payment_credit_register_receivable
12693     * @apiGroup Payment
12694     * @apiDescription This endpoint is used to display credit register receivable page in mobapp.
12695     * 
12696     * @apiParam {String} token user's API token.
12697     * 
12698     * @apiSuccess {View} Render Displays the credit register receivable page.
12699     * 
12700     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage for token is missing / not set.
12701     * @apiError {String} Error Throws error exception if memcache does not exist or expired.
12702     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if not a light plan user
12703     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if user is not subscribed to the zero discount option
12704     * 
12705     * @apiSuccessExample Success Response:
12706     * Displays the credit register receivable page.
12707     * 
12708     * @apiErrorExample Error Response Missing token / not set:
12709     * Redirects to {{ENV}}/mobapp/retrypage
12710     * 
12711     * @apiErrorExample Error Response Not a light plan user:
12712     * Redirects to {{ENV}}/mobapp/retrypage
12713     * 
12714     * @apiErrorExample Error Response memchache does not exist or expired.
12715     * Throws NotFoundException error
12716     * 
12717     * @apiErrorExample Error Response not subscribed to the zero discount option:
12718     * Redirects to {{ENv}}/mobapp/retrypage
12719     * 
12720     * @apiSampleRequest off
12721     */
12722    public function mobapp_payment_credit_register_receivable() {
12723        $retryPageUrl = myTools::getUrl() . '/mobapp/retrypage' . myTools::getMobappToken($_GET); 
12724
12725        // redirect to retry page if param token is not set
12726        if (!isset($this->request->query['token'])) {
12727            return $this->redirect($retryPageUrl);
12728        }
12729
12730        $userToken = $this->request->query['token'];
12731        $userData = $this->User->findByApiToken($userToken);
12732
12733        // redirect to retry page if token does not exist
12734        if (!$userData) {
12735            return $this->redirect($retryPageUrl);
12736        }
12737
12738        $user = $userData['User'];
12739
12740        // throw error exception if memcache does not exist or expired
12741        if (!$memcache_receivable_data = $this->memcache->get('memcache_receivable_data' . $user['id'])) {
12742            throw new NotFoundException();
12743        }
12744
12745        $zeusMaintenance = false;
12746        if (myTools::zeusMaintenancePeriod()){
12747            $zeusMaintenance = true;
12748        }
12749
12750        $isCardRegistered = false;
12751        if ((!empty($user['card_brand']) && !empty($user['card_number']))) {
12752            $isCardRegistered = true;
12753        }
12754
12755        $userObj = new UserTable($user);
12756        $membershipType = $userObj->getMembershipTypeIndex();
12757
12758        // redirect to retry page if not light plan
12759        if (!in_array($membershipType, Configure::read('membership_type_lightplan'))) {
12760            return $this->redirect($retryPageUrl);
12761        }
12762
12763        // get user active zero student discount option data
12764        $zeroStudentDiscountOptionTermData = $this->UserDiscountOptionsTerm->getTerm([
12765            'user_id' => $userObj->id,
12766            'discount_option_id' => Configure::read('discount_option.zero_student.plan_id'),
12767            'status' => 1
12768        ]);
12769
12770        // redirect to retry page if not zero discount option user
12771        if (!$zeroStudentDiscountOptionTermData) {
12772            return $this->redirect($retryPageUrl);
12773        }
12774
12775        $this->getAndSetCardInfo($user);
12776        $this->set('zeroStudentDiscountOptionUser', true);
12777        $this->set('zeus_maintenance', $zeusMaintenance);
12778        $this->set('isCardRegistered', $isCardRegistered);
12779        $this->set('zeusTransactionFlag', true);
12780        $this->set('amount', 0);
12781        $this->set('discountedAmount', 0);
12782        $this->request->query['renderPath'] = myTools::getDeviceUrl() . 'Payment/payment_credit_register_receivable';
12783
12784        $this->mobapp_credit_change();
12785    }
12786
12787    /**
12788     * @api {get} /mobapp/payment/credit_change/:token/:unli_option/:page_origin/:renderPath mobapp_credit_change()
12789     * @apiName mobapp_credit_change
12790     * @apiGroup Payment
12791     * @apiDescription This endpoint is used to change user's credit card information.
12792     * 
12793     * @apiParam {String} token User's API token
12794     * @apiParam {String} unli_option User's unli option. Blank if not provided
12795     * @apiParam {String} page_origin User's page origin. Null if not provided
12796     * @apiParam {String} renderPath User's render path. Null if not provided
12797     * 
12798     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/credit_change_form
12799     * 
12800     * @apiError {View} Redirect Redirects to {{ENV}}//mobapp/payment/wp_credit_change for non-JPY currency users
12801     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/payment/failure_family for family plan users
12802     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/payment/credit_retry for free users and non-corporate individual users
12803     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage for token is missing
12804     * 
12805     * @apiSuccessExample Success Response:
12806     * Redirects to {{ENV}}/mobapp/payment/credit_change_form
12807     * 
12808     * @apiErrorExample Error Response (Non-JPY Currency):
12809     * Redirects to {{ENV}}/mobapp/payment/wp_credit_change
12810     * 
12811     * @apiErrorExample Error Response (Family Plan):
12812     * Redirects to {{ENV}}/mobapp/payment/failure_family
12813     * 
12814     * @apiErrorExample Error Response (Free User):
12815     * Redirects to {{ENV}}/mobapp/payment/credit_retry
12816     * 
12817     * @apiErrorExample Error Response (Token Missing):
12818     * Redirects to {{ENV}}/mobapp/retrypage
12819     * 
12820     * @apiSampleRequest off
12821     */
12822    public function mobapp_credit_change() {
12823        $this->blockWithdrawnSapuriToS('mobapp');
12824        $this->disablePageForSapuri('mobapp');
12825        // set variables
12826        $this->layout = "mobapp";
12827        $urlParams = myTools::getMobappToken($_GET);
12828        $logFileName = 'card_change';
12829        $formType = Configure::read('payment_credit_change');
12830        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType)); // get user data and validate
12831        $amount = $userData['PaymentPlanPrice']['amount'];
12832        $userData = $userData['User'];
12833        $apiToken = $this->request->query['token'];
12834        $fromUnliOption = isset($this->request->query['unli_option']) ? $this->request->query['unli_option'] : '';
12835        $urlRedirect = isset($this->request->query['page_origin']) ? $this->request->query['page_origin'] : null ;
12836        $renderPath = isset($this->request->query['renderPath']) ? $this->request->query['renderPath'] : null;
12837
12838        $userObj = new UserTable($userData);
12839        $membershipTypeIndex = $userObj->getMembershipTypeIndex();
12840        if(
12841            $membershipTypeIndex !== null &&
12842            (
12843                (
12844                    in_array($membershipTypeIndex, Configure::read('store_credit_form_memberships')) && 
12845                    !empty($userData['User']['corporate_id'])
12846                ) || 
12847                in_array($membershipTypeIndex, Configure::read('common_corporate_payment_memberships'))
12848            )
12849        ) {
12850            if ($fromUnliOption) {
12851                return $this->redirect(myTools::getUrl() . '/mobapp/common_corporate_payment?type=' . Configure::read('payment_url_type.corporate_type.corporate_change_payment_credit') . '&token=' . $apiToken . '&from_page=6&unli_option=' . $fromUnliOption); // 6 is from option page
12852            } else {
12853                return $this->redirect(myTools::getUrl() . '/mobapp/common_corporate_payment?type=' . Configure::read('payment_url_type.corporate_type.corporate_change_payment_credit') . '&token=' . $apiToken. '&from_page=account');
12854            }
12855        }
12856    
12857        // redirect to worldpay if not zuespay user (currency != JPY)
12858        if ($userData['currency_code'] != Configure::read('currency_jpy')) {
12859            return $this->redirect(myTools::getUrl() . '/mobapp/payment/wp_credit_change'.$urlParams);
12860        }
12861
12862        // redirect to family failure page if family plan
12863        if (isset($userData['parent_id']) && $userData['parent_id']) {
12864            return $this->redirect(myTools::getUrl() . '/mobapp/payment/failure_family'.$urlParams);
12865        }
12866
12867        // free user and not corporate individual user
12868        if (
12869            ($userData['charge_flg'] == 0 || $userData['fail_flg'] == 1) &&
12870            !in_array($userData['payment_plan_id'], myTools::getIndividualPaymentPlanIds())
12871        ) {
12872            return $this->redirect(myTools::getUrl() . '/mobapp/payment/credit_retry'.$urlParams);
12873        }
12874
12875        // get request data
12876        $requestData = $this->request->query;
12877
12878        // clear error memcache
12879        $this->memcache->delete('error-'.$apiToken);
12880
12881        // clear previously set card tokens and set new token
12882        $this->memcache->delete('cardchange-token-'.$apiToken);
12883
12884        $cardToken = md5(uniqid(rand(), true));
12885
12886        $this->memcache->set(array(
12887            'key' => 'cardchange-token-'.$apiToken,
12888            'value' => $cardToken,
12889            'expire' => 3600
12890        ));
12891
12892        $userData = $this->changePaymentPlanIfTelecomUser($userData);
12893        // set payment amount
12894        $userData['paymentAmount'] = 0;
12895
12896        // if corporate user
12897        if (isset($userData['corporate_id']) && $userData['corporate_id']) {
12898            $userData['corporateSettlementType'] = Configure::read('corporate_settlement_types.change_card');
12899        }
12900
12901        // set transactin error to 0 if failed to create payment transaction
12902        if (!$pt = $this->createPaymentTransaction($formType, $userData)) {
12903            $this->set('transactionError', 1);
12904        }
12905
12906        // fetch and delete card error
12907        if ($error = $this->memcache->get('card-error-'.$apiToken)) {
12908            $this->memcache->delete('card-error-'.$apiToken);
12909        }
12910        if ($urlRedirect) {
12911            $urlRedirect = "&page_origin=".$urlRedirect;
12912        }
12913
12914        // - NJ-23812 redirect to credit change form
12915        if (isset($fromUnliOption) && !empty($fromUnliOption)) {
12916            $newUrlParams = "?token=".$apiToken.'&cardToken='.$cardToken.'&paymentHash='.$pt['payment_hash'].'&unli_option='.$fromUnliOption;
12917        } else {
12918            $newUrlParams = "?token=".$apiToken.'&cardToken='.$cardToken.'&paymentHash='.$pt['payment_hash'].$urlRedirect;
12919        }
12920
12921        if (!$renderPath) {
12922            return $this->redirect(myTools::getUrl() . '/mobapp/payment/credit_change_form'.$newUrlParams);
12923        }
12924
12925        // set view variables
12926        $this->response->disableCache();
12927        $this->setSupportPayPal($userData);
12928        $this->set('urlRedirect', $urlRedirect);
12929        $this->set('error', $error);
12930        $this->set('cardToken', $cardToken);
12931        $this->set('apiToken', $apiToken);
12932        $this->set('title_for_layout', '再入会');
12933        $this->set('paymentHash', $pt['payment_hash']);
12934        $this->set('userApiToken', $apiToken);
12935
12936        if ($renderPath) {
12937            $this->render($renderPath);
12938        } else {
12939            $this->render(myTools::getDeviceUrl() . 'Payment/credit_change');
12940        }
12941    }
12942
12943    /**
12944     * @api {get} /mobapp/payment/wp_credit_change/:token mobapp_wp_credit_change()
12945     * @apiName mobapp_wp_credit_change
12946     * @apiGroup Payment
12947     * @apiDescription This endpoint is used to redirect to change user's credit card information.
12948     * 
12949     * @apiParam {String} token User's API token
12950     * 
12951     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/wp_credit_change_form
12952     * 
12953     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if token is missing
12954     * 
12955     * @apiSuccessExample Success Response:
12956     * Redirects to {{ENV}}/mobapp/payment/wp_credit_change_form
12957     * 
12958     * @apiErrorExample Error Response:
12959     * Redirects to {{ENV}}/mobapp/retrypage
12960     * 
12961     * @apiSampleRequest off
12962     */
12963    public function mobapp_wp_credit_change() {
12964        $this->blockWithdrawnSapuriToS('mobapp');
12965        $this->disablePageForSapuri('mobapp');
12966        // set variables
12967        $logFileName = 'card_change';
12968        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => Configure::read('payment_credit_change')));
12969        $apiToken = $userData['User']['api_token'];
12970        $this->layout = "mobapp";
12971        $this->response->disableCache();
12972        $urlParams = myTools::getMobappToken($_GET);
12973
12974        // get error from memcache
12975        $error = $this->memcache->get('card_change_error_'.$apiToken);
12976
12977        // check if there is error
12978        if ($error) {
12979            $this->memcache->delete('card_change_error_'.$apiToken);
12980            $this->set('error', $error);
12981        }
12982
12983        // set view variables
12984        $this->set('apiToken', $apiToken);
12985        $this->set('title_for_layout', '再入会');
12986        $this->render(myTools::getDeviceUrl() . 'Payment/wp_credit_change');
12987
12988        // NJ-23812 redirect to change form
12989        return $this->redirect(myTools::getUrl() . '/mobapp/payment/wp_credit_change_form'.$urlParams);
12990    }
12991
12992    /**
12993     * @api {get} /mobapp/payment/wp_credit_change_form/:token mobapp_wp_credit_change_form()
12994     * @apiName mobapp_wp_credit_change_form
12995     * @apiGroup Payment
12996     * @apiDescription This endpoint is used to change user's credit card information.
12997     * 
12998     * @apiParam {String} token User's API token
12999     * 
13000     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/close?token={$apiToken}&type=card_change{$addWelcomeModalParams} afrer successful card change
13001     * 
13002     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if token is missing
13003     * 
13004     * @apiSuccessExample Success Response:
13005     * Redirects to {{ENV}}/mobapp/close?token={$apiToken}&type=card_change{$addWelcomeModalParams}
13006     * 
13007     * @apiErrorExample Error Response:
13008     * Redirects to {{ENV}}/mobapp/retrypage
13009     * 
13010     * @apiSampleRequest off
13011     */ 
13012    public function mobapp_wp_credit_change_form() {
13013        $this->blockWithdrawnSapuriToS('mobapp');
13014        $this->disablePageForSapuri('mobapp');
13015        // set variables
13016        $logFileName = 'card_change';
13017        $formType = Configure::read('payment_credit_change');
13018        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType));
13019        $apiToken = $userData['User']['api_token'];
13020        $user = $this->sharedUserData['User'];
13021        $this->layout = "mobapp";
13022        $this->response->disableCache();
13023        
13024        // get error from memcache
13025        $error = $this->memcache->get('card_change_error_'.$apiToken);
13026        
13027        // check if there is error
13028        if ($error) {
13029            $this->memcache->delete('card_change_error_'.$apiToken);
13030            $this->set('error', $error);
13031        }
13032        
13033
13034        // check if allowed aftee
13035        $this->checkAfteeSupported($userData['User']);
13036        // NJ-23812 : display payment plan 
13037        $this->setPaymentPlanDetails($userData['User'],Configure::read('payment_plans.premium_plan'),$logFileName);
13038
13039        if ($this->Session->read('mobapp_show_welcome_back_modal')) {
13040            $this->Session->delete('mobapp_show_welcome_back_modal');
13041        }
13042
13043        $addWelcomeModalParams = "&re_enrolled=1";
13044
13045        $isCardRegistered = (!empty($user['card_brand']) && !empty($user['card_number'])) ? true : false;
13046        
13047        $this->set('isCardRegistered', $isCardRegistered);
13048        $this->set('cardNumber', $user['card_number']);
13049        $this->set('cardBrand', $user['card_brand']);
13050        $this->set('cardLogo', myTools::getWorldpayCardLogo($user['card_brand']));
13051
13052        // set view variables
13053        $this->set('pmtValue', 'auth');
13054        $this->set('apiToken', $apiToken);
13055        $this->set('logFileName', $logFileName);
13056        $this->set('worldpayFlg', true);
13057        $this->set('memKeyError', 'card_change_error_'.$apiToken);
13058        $this->set('referrer', urlencode(myTools::getUrl()."/mobapp/payment/wp_credit_change_form?token={$apiToken}"));
13059        $this->set('successUrl', urlencode(myTools::getUrl()."/user/mobapp/close?token={$apiToken}&type=card_change{$addWelcomeModalParams}"));
13060        $this->set('formType', $formType);
13061        $this->set('title_for_layout', __d('payment','お支払い方法変更'));
13062        $this->render(myTools::getDeviceUrl() . 'Payment/wp_credit_change_form');
13063    }
13064
13065    /**
13066     * @api {post} /mobapp/payment/credit_change_form/:token/:unli_option/:cardToken/:page_origin/:paymentHash mobapp_credit_change_form()
13067     * @apiName mobapp_credit_change_form
13068     * @apiGroup Payment
13069     * @apiDescription This endpoint is used to process user's credit card information change.
13070     * 
13071     * @apiParam {String} token User's API token
13072     * @apiParam {String} unli_option if User is from unli option. Blank if not provided
13073     * @apiParam {String} cardToken User's card token. Blank if not provided
13074     * @apiParam {Number} page_origin User's page origin. Null if not provided. 1 - store, 2 - ebook
13075     * @apiParam {String} paymentHash User's payment hash.
13076     * 
13077     * @apiBody {String} token User's API token
13078     * @apiBody {Object} ZPaymentFullLogs Payment full logs
13079     * @apiBody {String} ZPaymentFullLogs.card_change Set to 'yes'
13080     * @apiBody {String} ZPaymentFullLogs.telno telephone number of zeus
13081     * @apiBody {String} ZPaymentFullLogs.clientip client ip address
13082     * @apiBody {String} ZPaymentFullLogs.paymentHash User's payment hash
13083     * 
13084     * @apiSuccess {View} Success Redirects to {{ENV}}/mobapp/store/card_register_complete if from store
13085     * @apiSuccess {View} Success Redirects to {{ENV}}//mobapp/option/native-start if from unlimited option
13086     * 
13087     * @apiError {View} Redirect {{ENV}}/mobapp/payment/credit_change?token=  if there's an error
13088     * @apiError {View} Redirect {{ENV}}/mobapp/payment/credit_change_form?token=&page_origin= if user is from store or ebook
13089     * @apiError {View} Redirect {{ENV}}/mobapp/retrypage if payment hash is missing
13090     * 
13091     * @apiSuccessExample Success Response (From Store):
13092     * Redirects to {{ENV}}/mobapp/store/card_register_complete
13093     * 
13094     * @apiSuccessExample Success Response (From Unlimited Option):
13095     * Redirects to {{ENV}}//mobapp/option/native-start
13096     * 
13097     * @apiErrorExample Error Response:
13098     * Redirects to {{ENV}}/mobapp/payment/credit_change?token=
13099     * 
13100     * @apiErrorExample Error Response (From Store or Ebook):
13101     * Redirects to {{ENV}}/mobapp/payment/credit_change_form?token=&page_origin=
13102     * 
13103     * @apiErrorExample Error Response (Payment Hash Missing):
13104     * Redirects to {{ENV}}/mobapp/retrypage
13105     * 
13106     * @apiSampleRequest off
13107     */
13108    public function mobapp_credit_change_form() {
13109
13110        // - NJ-23812
13111        if ($this->Session->read('credit_skip_to_confirmation')) {
13112            $this->Session->delete('credit_skip_to_confirmation');
13113        }
13114
13115        if ($this->Session->read('mobapp_show_welcome_back_modal')){
13116            $this->Session->delete('mobapp_show_welcome_back_modal');
13117        }
13118
13119
13120        $this->blockWithdrawnSapuriToS('mobapp');
13121        $this->disablePageForSapuri('mobapp');
13122        $this->layout = "mobapp";
13123        $urlParams = myTools::getMobappToken($_GET);
13124        $formType = Configure::read('payment_credit_change');
13125        $userData = $this->mobappGetUserData(array('logFileName' => 'card_change', 'formType' => $formType)); // get user data and validate
13126        $apiToken = $this->request->query['token'];
13127        $fromUnliOption = isset($this->request->query['unli_option']) ? $this->request->query['unli_option'] : '';
13128        $cardToken = isset($this->request->query['cardToken']) ? $this->request->query['cardToken'] : '';
13129        $cardToken = isset($this->request->query['cardToken']) ? $this->request->query['cardToken'] : '';
13130        $urlRedirect = isset($this->request->query['page_origin']) ? $this->request->query['page_origin'] : null;
13131        $isZeusUser = isset($userData['card_company']) && $userData['card_company'] == 1 ? true : false;
13132        $userObj = new UserTable($userData);
13133        $membershipTypeIndex = $userObj->getMembershipTypeIndex();
13134        if(
13135            $membershipTypeIndex !== null &&
13136            (
13137                (
13138                    in_array($membershipTypeIndex, Configure::read('store_credit_form_memberships')) && 
13139                    !empty($userData['User']['corporate_id'])
13140                ) || 
13141                in_array($membershipTypeIndex, Configure::read('common_corporate_payment_memberships'))
13142            )
13143        ) {
13144            if ($fromUnliOption) {
13145                return $this->redirect(myTools::getUrl() . '/mobapp/common_corporate_payment?type=' . Configure::read('payment_url_type.corporate_type.corporate_change_payment_credit') . '&token=' . $apiToken . '&from_page=6'); // 6 is from option page
13146            } else {
13147                return $this->redirect(myTools::getUrl() . '/mobapp/common_corporate_payment?type=' . Configure::read('payment_url_type.corporate_type.corporate_change_payment_credit') . '&token=' . $apiToken);
13148            }
13149        }
13150
13151        if (!isset($this->request->query['paymentHash'])) {
13152            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
13153        }
13154
13155        $paymentHash = $this->request->query['paymentHash'];
13156
13157        // delete payment gateway type memcache
13158        $this->memcache->delete('mobappCreditChangePaymentGatewayType_' . $apiToken);
13159
13160        // check if there's a post data
13161        if ($this->request->is('post')) {
13162            $data = $this->request->data;
13163            $data['token'] = $apiToken;
13164            $data['ZPaymentFullLogs']['card_change'] = 'yes';
13165            $data['ZPaymentFullLogs']['telno'] = Configure::read('credit.default_telno');
13166            $data['ZPaymentFullLogs']['clientip'] = Configure::read('ZEUS_clientip');
13167            $data['ZPaymentFullLogs']['paymentHash'] = $paymentHash;
13168
13169            // check url redirect
13170            if ($urlRedirect) {
13171                $data["page_origin"] = $urlRedirect;
13172            }
13173
13174            // check if token matches token in session
13175            $checkToken = $this->checkTokenMobapp($apiToken, $cardToken, 'cardchange-token-');
13176
13177            // check if token is true
13178            if ($checkToken) {
13179                $this->unsetTokenMobapp($apiToken, 'cardchange-token-');
13180                $this->zeus_card_process_mobapp(array(
13181                    'data' => $data,
13182                    'form_type' => $formType,
13183                    'referrer' =>  myTools::getUrl() . "/mobapp/payment/credit_change?token=" . $apiToken,
13184                    'api_token' => $apiToken,
13185                    'unli_option' => $fromUnliOption
13186                ));
13187            } else {
13188                $urlErrRedirect = "/mobapp/payment/credit_change?token=" . $apiToken;
13189                // check for page origin 1 - store, 2 - ebook
13190                if ($urlRedirect) {
13191                    $urlErrRedirect = $urlErrRedirect."&page_origin=".$urlRedirect;
13192                }
13193                // set error message
13194                $this->memcache->set(array(
13195                    'key' => 'card-error-'.$apiToken,
13196                    'value' => 'ERROR : Card validation token mismatch.',
13197                    'expire' => 3600
13198                ));
13199                return $this->redirect(myTools::getUrl() . $urlErrRedirect);
13200            }
13201        }
13202
13203        // NJ-30828: set view to display user's paypal email
13204        $this->setPaypalUser($userData);
13205
13206        // NJ-23812 : set view to display payment plan
13207        $this->setPaymentPlanDetails($userData['User'],Configure::read('payment_plans.premium_plan'),'card_change');
13208        $this->setSupportPayPal($userData['User']);
13209
13210        $this->set('cardBrand', $userData['User']['card_brand']);
13211        $this->set('cardNumber', $userData['User']['card_number']);
13212        $this->set('cardLogo', myTools::getWorldpayCardLogo($userData['User']['card_brand']));
13213        
13214        // - set support paypal
13215        $this->set('paypalUserData', $userData['User']);
13216
13217        // get user data for further processing
13218        $this->set('error', $this->memcache->get('error-'.$apiToken));
13219        $this->set('title_for_layout', '再入会');
13220        $this->set('zeusTransactionFlag', true);
13221        $this->set('amount', 0);
13222        $this->set('paymentHash', $paymentHash);
13223        $this->set('userApiToken', $apiToken);
13224        $this->set('apiToken', $apiToken);
13225        $this->set('title_for_layout', __d('payment','お支払い方法変更'));
13226        $this->set('failURLReferer', myTools::getUrl() . "/mobapp/payment/credit_change" . myTools::getMobappToken(array_merge(array('token' => $apiToken ), $_GET)) );
13227        $this->render(myTools::getDeviceUrl() . 'Payment/credit_change_form');
13228    }
13229    /**
13230     * @api {get} /mobapp/payment/paypal_payment_credit_change_proccess/:token mobapp_paypal_credit_change_process()
13231     * @apiName mobapp_paypal_credit_change_process
13232     * @apiGroup Payment
13233     * @apiDescription This endpoint is used to process user's credit card information change using paypal.
13234     * 
13235     * @apiParam {String} token User's API token
13236     * 
13237     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/close?token={$apiToken}&type=card_change after successful card change
13238     * 
13239     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/payment/credit_change?token= if there's an error
13240     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if token is missing
13241     * 
13242     * @apiSuccessExample Success Response:
13243     * Redirects to {{ENV}}/mobapp/close?token={$apiToken}&type=card_change
13244     * 
13245     * @apiErrorExample Error Response Settlement Failed:
13246     * Redirects to {{ENV}}/mobapp/payment/credit_change?token=
13247     * 
13248     * @apiErrorExample Error Response Token Missing:
13249     * Redirects to {{ENV}}/mobapp/retrypage
13250     * 
13251     * @apiSampleRequest off
13252     */
13253    public function mobapp_paypal_credit_change_process() {
13254        $this->autoRender = false;
13255        $this->layout = false;
13256        $logFileName = 'paypal_debug';
13257
13258        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => Configure::read('payment_credit_change')));
13259        $user = $userData['User'];
13260        $apiToken = $this->request->query['token'];
13261
13262        $data = array(
13263            'paymentPlanData' => array(
13264                'paymentPlanId' => $user['payment_plan_id'],
13265                'priceId' => $user['price_id']
13266            ),
13267            'formType' => Configure::read('payment_credit_change')
13268        );
13269
13270        // process paypal settlement
13271        $result = $this->paypalSaveBillingAgreement($data, $user);
13272
13273        // redirect to reregister page if result is false
13274        if (!$result['success']) {
13275            // set the memcache error
13276            $this->memcache->set(array(
13277                'key' => 'card-error-'.$apiToken,
13278                'value' => __("Error : 決済失敗"),
13279                'expire' => 3600 // 1 hour
13280            ));
13281
13282            $memKey = 'paypalBillingAgreementData_' . $apiToken;
13283
13284            // delete memcache billing agreement data
13285            if ($this->memcache->get($memKey)) {
13286                $this->memcache->delete($memKey);
13287            }
13288
13289            $result['status'] = 0;
13290
13291            // update payment transaction
13292            $this->PaymentTransaction->paypalUpdatePaymentTransaction($result);
13293
13294            $this->memcache->set(array(
13295                'key' => 'mobappCreditChangePaymentGatewayType_' . $apiToken,
13296                'value' => Configure::read('card_company.paypal'),
13297                'expire' => 3600 //  1 hour
13298            ));
13299
13300            return $this->redirect(myTools::getUrl() . "/mobapp/payment/credit_change?token=" . $apiToken);
13301        }
13302
13303        // redirect to notice to user page
13304        return $this->redirect(array('controller' => 'Mobapp', 'action' => 'close', '?' => array('token' => $apiToken, 'type' => 'card_change')));
13305    }
13306
13307    /**
13308     * @api {get} /mobapp/payment/credit_retry/:token mobapp_credit_retry()
13309     * @apiName mobapp_credit_retry
13310     * @apiGroup Payment
13311     * @apiDescription This endpoint is used to display user's credit card retry page.
13312     * 
13313     * @apiParam {String} token User's API token
13314     * 
13315     * @apiSuccess {View} Render Displays user's credit card retry page
13316     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/wp_credit_retry for non-JPY currency users
13317     * 
13318     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if token is missing or empty payment data
13319     * 
13320     * @apiSuccessExample Success Response (JPY Currency):
13321     * Displays user's credit card retry page
13322     * 
13323     * @apiSuccessExample Success Response (Non-JPY Currency):
13324     * Redirects to {{ENV}}/mobapp/payment/wp_credit_retry
13325     * 
13326     * @apiErrorExample Error Response:
13327     * Redirects to {{ENV}}/mobapp/retrypage
13328     * 
13329     * @apiSampleRequest off
13330     */ 
13331    public function mobapp_credit_retry() {
13332
13333        // - NJ-23812 : reset  
13334        if ($this->Session->read('credit_skip_to_confirmation')){
13335            $this->Session->delete('credit_skip_to_confirmation');
13336        }
13337
13338        $this->response->disableCache();
13339        $this->blockWithdrawnSapuriToS('mobapp');
13340        $this->disablePageForSapuri('mobapp');
13341        
13342        // set variables
13343        $this->layout = 'mobapp';
13344        $urlParams = myTools::getMobappToken($_GET);
13345        $logFileName = 'card_retry';
13346        $formType = Configure::read('payment_credit_retry');
13347        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType)); // get user data and validate
13348        $amount = $userData['PaymentPlanPrice']['amount'];
13349        $userData = $userData['User'];
13350        $apiToken = $this->request->query['token'];
13351
13352        $memKeyPaypal = 'mobappPaypalPaymentCreditRetryData_' . $apiToken;
13353        // delete memcache payment gateway type
13354        if ($this->memcache->get($memKeyPaypal)) {
13355            $this->memcache->delete($memKeyPaypal);
13356        }
13357
13358        // delete payment gateway type memcache
13359        $this->memcache->delete('mobappCreditRetryPaymentGatewayType_' . $apiToken);
13360
13361        // - if user is lite plan
13362        $paymentPlanId = $userData['payment_plan_id'];
13363        $isLitePlanUser = in_array($paymentPlanId, Configure::read('lite_payment_plans')) ? true : false;
13364
13365        // - check price id
13366        if (
13367            !isset($userData['price_id']) || 
13368            empty($userData['price_id']) & 
13369            $isLitePlanUser &&
13370            isset($userData['currency_code'])
13371        ) {
13372            $lightPlanData = $this->PaymentPlanPrice->getPaymentData(array(
13373                'currencyCode' => $userData['currency_code'],
13374                'paymentPlanId' => Configure::read('payment_plans.light_plan')
13375            ));
13376
13377            // if empty
13378            if (!$lightPlanData) {
13379                return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
13380            }
13381            
13382            // price id
13383            $userData['price_id'] = $lightPlanData['priceId'];
13384        }
13385
13386        // redirect to retry page if empty payment data and payment plan id or price id is null
13387        if (!$pData = $this->getRetryPaymentData($userData, $logFileName)) {
13388            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
13389        }
13390
13391        
13392
13393        //- new chocotto plan
13394        if ($pData['paymentPlanId'] == Configure::read('payment_plans.chocotto_plan')) {
13395            $formType = Configure::read('payment_credit_chocotto_retry');
13396        }
13397
13398        // redirect to worldpay if not zuespay user (currency != JPY)
13399        if ($userData['currency_code'] != Configure::read('currency_jpy')) {
13400            return $this->redirect(myTools::getUrl() . '/mobapp/payment/wp_credit_retry'.$urlParams);
13401        }
13402
13403        $userData['payment_plan_id'] = $pData['paymentPlanId'];
13404        $userData['price_id'] = $pData['priceId'];
13405        $amount = $pData['amount'];
13406
13407        // NC-3914
13408        $this->getAndSetCardInfo($userData);
13409
13410        // clear error memcache
13411        $this->memcache->delete('error-'.$apiToken);
13412
13413        // clear previously set card tokens and set new token
13414        $this->memcache->delete('cardretry-token-'.$apiToken);
13415
13416        $cardToken = md5(uniqid(rand(), true));
13417
13418        // set memcache
13419        $this->memcache->set(array(
13420            'key' => 'cardretry-token-'.$apiToken,
13421            'value' => $cardToken,
13422            'expire' => 3600
13423        ));
13424
13425        $userData = $this->changePaymentPlanIfTelecomUser($userData);
13426
13427        $corporateIndiUser = false;
13428        $cpAmount = 0;
13429
13430        // - check if empty corporate type -> add corporate type base on user's payment plan id
13431        if (
13432            isset($userData['corporate_id']) &&
13433            $userData['corporate_id'] &&
13434            (!isset($userData['corporate_type']) || !$userData['corporate_type'])
13435        ) {
13436            $userData['corporate_type'] = myTools::getCoporateTypeUsingPaymentPlanId($pData['paymentPlanId']);
13437        }
13438        $corpType = myTools::getCoporateTypeUsingPaymentPlanId($userData['payment_plan_id']);
13439        // if corporate user
13440        if (
13441            isset($userData['corporate_id']) && 
13442            $userData['corporate_id'] &&
13443            isset($userData['payment_plan_id']) &&
13444            $userData['payment_plan_id']
13445        ) {
13446            $corporateTaxRate = Configure::read('tax.increase');
13447            $corporateIndiUser = true;
13448            if ($userData['payment_plan_id'] == Configure::read('payment_plans.corporate_light_individual_plan')) {
13449                $getCorpMemberReceivable = $this->CorporatePaymentMemberReceivable->memberReceivable( array("user_id" => $userData['id']) );
13450                $amount = isset($getCorpMemberReceivable["total"]) ? $getCorpMemberReceivable["total"] : 0 ;
13451                $basicFee = isset($getCorpMemberReceivable["basic_fee"]) ? $getCorpMemberReceivable["basic_fee"] : 0 ;
13452                $basicFeeWoTax = isset($getCorpMemberReceivable["basic_fee_wo_tax"]) ? $getCorpMemberReceivable["basic_fee_wo_tax"] : 0;
13453                $userData['lesson_fee'] = isset($getCorpMemberReceivable["lesson_fee"]) ? $getCorpMemberReceivable["lesson_fee"] : 0 ;
13454                $userData['basic_fee'] = $basicFee ;
13455                $userData['paymentAmount'] = $amount;
13456                $cpAmount = $basicFeeWoTax;
13457                $userData['corporateSettlementType'] = Configure::read('corporate_settlement_types.retry_payment');
13458            } elseif (
13459                $userData['payment_plan_id'] == Configure::read('payment_plans.corporate_standard_individual_plan') ||
13460                $userData['payment_plan_id'] == Configure::read('payment_plans.corporate_premium_individual_plan')
13461            ) {
13462                
13463                $unpaidReceivableParams = array(
13464                    'userId' => $userData['id'],
13465                    'corporateId' => $userData['corporate_id'],
13466                    'corporateType' => $corpType
13467                );
13468
13469                // get unpaid receivable
13470                $unpaidReceivable = $this->CorporatesPaymentReceivable->getIndiUnPaidReceivable($unpaidReceivableParams);
13471
13472                // generate corporate payment receivable if no unpaid corporate payment receivable
13473                if (!$unpaidReceivable) {
13474                    $corpType = $corpType;
13475                    $corpTypeStandard = Configure::read('corporate_type.standard');
13476                    $corpTypePremium = Configure::read('corporate_type.premium');
13477
13478                    $cprTypes = array(
13479                        Configure::read('corporate_type.standard') => $this->CorporatesPaymentReceivable->typeCorporateStandard,
13480                        Configure::read('corporate_type.premium') => $this->CorporatesPaymentReceivable->typeCorporatePremium
13481                    );
13482
13483                    // get payment plan data
13484                    $monthlyPaymentData = $this->PaymentPlanPrice->getPaymentData(array(
13485                        'currencyCode' => $userData['currency_code'],
13486                        'paymentPlanId' => $userData['payment_plan_id']
13487                    ));
13488
13489                    $cprDiscount = (int)$this->CorporateDiscountRate->getDiscount(array(
13490                        'corporateId' => $userData['corporate_id'], 
13491                        'corporateType' => $corpType
13492                    ));
13493
13494                    $insertCPRData = array(
13495                        'corporate_id' => $userData['corporate_id'],
13496                        'user_id' => $userData['id'],
13497                        'type' => isset($cprTypes[$corpType]) ? $cprTypes[$corpType] : 0,
13498                        'status' => 0, // unpaid
13499                        'quantity' => 1,
13500                        'amount' => $monthlyPaymentData['amount'],
13501                        'discount' => $cprDiscount,
13502                        'next_settlement' => date('Y-m-d 00:00:00')
13503                    );
13504
13505                    $unpaidReceivable = array(
13506                        'amount' => $monthlyPaymentData['amount'],
13507                        'discount' => $cprDiscount
13508                    );
13509
13510                    // create corporate payment receivable
13511                    if (!$this->CorporatesPaymentReceivable->addReceivablePayment($insertCPRData)) {
13512                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to create payment receivable.', $userData);
13513                        return ;
13514                    }
13515
13516                }
13517                $amount = $cpAmount = $unpaidReceivable['amount'] - $unpaidReceivable['discount'];
13518                $userData['paymentAmount'] = (int)($amount * $corporateTaxRate);
13519                $amount = (int)($amount * $corporateTaxRate);
13520                $userData['updateCorporateReceivable'] = true;
13521                $userData['corporateSettlementType'] = Configure::read('corporate_settlement_types.retry_payment');
13522            }
13523        } else {
13524            // set payment
13525            $userData['paymentAmount'] = $amount;
13526        }
13527        
13528        // NJ-47740
13529        $coupon = $this->UsersCouponV1->getCouponUseRequest(array(
13530            'userId' => $userData['id'],
13531            'kbn' => Configure::read('coupon_kbn.monthly_settlement')
13532        ));
13533        
13534        if (
13535            !empty($coupon['result']) && 
13536            !empty($coupon['grp_id']) && 
13537            !empty($coupon['amount']) && 
13538            empty($coupon['has_payment']) // exclude if coupon has payment
13539        ) {
13540            $userData['monthlyDiscount'] = $coupon['amount'];
13541            $userData['monthly_grp_id'] = $coupon['grp_id'];
13542        }
13543        // NJ-47740 end
13544
13545        // NJ-23812: set receivable
13546        $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userData['id']);
13547        $appreciationPayment = $this->PaymentReceivable->computeReceivableReservationPayment($userData['id'], false, Configure::read('appreciation_data.payment_element_type'));
13548        $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userData['id'], false, Configure::read('payment_element_type.live'));
13549
13550        // add reserve receivable
13551        $userData['paymentAmount'] += $receivablePayment;
13552
13553        // add appreciation lesson receivable
13554        $userData['paymentAmount'] += $appreciationPayment;
13555
13556        // add live lesson receivable
13557        $userData['paymentAmount'] += $liveLessonReceivable;
13558
13559        // get user active annual discount option
13560        $annualDiscountOptionData = $this->UserDiscountOptionsTerm->getTerm([
13561            'user_id' => $userData['id'],
13562            'discount_option_id' => Configure::read('discount_option.annual.plan_id'),
13563            'status' => 1
13564        ]);
13565
13566        if ($annualDiscountOptionData) {
13567            unset($annualDiscountOptionData['contract_start']);
13568            $annualDiscountOptionData += [
13569                'dosh_event' => Configure::read('discount_option.dosh_event.annual_discount'),
13570                'dosh_status' => Configure::read('discount_option.dosh_status.monthly_discount')
13571            ];
13572            $userData['annualDiscountOption'] = $annualDiscountOptionData;
13573            $userData['paymentAmount'] -= $annualDiscountOptionData['amount'];
13574        }
13575
13576        // set transaction error to 1 if failed to create payment transaction
13577        if (!$pt = $this->createPaymentTransaction($formType, $userData)) {
13578            $this->set('transactionError', 1);
13579        }
13580
13581        // fetch and delete card error
13582        if ($error = $this->memcache->get('card-error-'.$apiToken)) {
13583            $this->memcache->delete('card-error-'.$apiToken);
13584        }
13585
13586        $sessionPaypalParams = array(
13587            'token' => "",
13588            'payment_gateway_type' => Configure::read('card_company.paypal'),
13589            'ZPaymentFullLogs' => array(
13590                'money' => $amount,
13591                'paymentHash' => $pt['payment_hash'],
13592                'discounted_amount' => (isset($userData['discounted_amount'])) ? $userData['discounted_amount'] : 0,
13593                'monthlyDiscount' => (isset($userData['monthlyDiscount'])) ? $userData['monthlyDiscount'] : 0,
13594                'monthly_grp_id' => (isset($userData['monthly_grp_id'])) ? $userData['monthly_grp_id'] : 0
13595            ),
13596            'paymentPlanData' => $pData,
13597            'receivablePayment' => $receivablePayment,
13598            'appreciationReceivable' => $appreciationPayment,
13599            'liveLessonReceivable' => $liveLessonReceivable,
13600            'liveLessonReceivable' => $liveLessonReceivable,
13601            'formType' => $formType
13602        );
13603
13604        if ($annualDiscountOptionData) {
13605            $sessionPaypalParams['annualDiscountOption'] = $annualDiscountOptionData;
13606        }
13607
13608        // NC-7029: coupon discount        
13609        if (!empty($userData['monthlyDiscount']) && !empty($userData['monthly_grp_id'])) {
13610            $sessionPaypalParams['monthlyDiscount'] = $userData['monthlyDiscount'];
13611            $sessionPaypalParams['monthly_grp_id'] = $userData['monthly_grp_id'];
13612        }
13613
13614        $this->memcache->set(array(
13615            'key' => 'mobappPaypalPaymentCreditRetryData_' . $apiToken,
13616            'value' => $sessionPaypalParams,
13617            'expire' => 3600 // 1 hour
13618        ));
13619
13620        // NJ-30828: set view to display user's paypal email
13621        $this->setPaypalUser($userData);
13622
13623        // NJ-23812 : set view var 
13624        $this->set('corporateIndiUser', $corporateIndiUser);
13625        $this->set('cpAmount',$cpAmount);
13626        $this->set('ppFormatAmount',number_format($amount));
13627
13628        // - NJ-23812 : support paypal
13629        $this->setSupportPayPal($userData);
13630        $this->set('paypalFlg', true);
13631        $this->set('paypalUserData', $userData);
13632        $this->set('userApiToken', $apiToken);
13633        $this->set('fAmount', myTools::formatAmount($amount));
13634
13635        $currencyData = $this->Currency->getSymbolAndPosition($user['currency_code']);
13636        $this->set('currencyData', $currencyData);
13637        $this->set('monthlyPriceSymbol',myTools::getCurrencySymbol($user['currency_code']));
13638
13639        // set view variables
13640        $this->set('data', $this->memcache->get('mobappUserCreditRetryInfo_'.$apiToken));
13641        $this->set('error', $error);
13642        $this->set('cardToken', $cardToken);
13643        $this->set('apiToken', $apiToken);
13644        $this->set('title_for_layout', __d('payment','お支払い方法変更'));
13645        $this->set('zeusTransactionFlag', true);
13646        $this->set('paymentHash', $pt['payment_hash']);
13647        $this->set('amount', $amount);
13648        $this->set('discountedAmount', (isset($userData['discounted_amount']) ? $userData['discounted_amount'] : 0));
13649        $this->set('failURLReferer', myTools::getUrl() . "/mobapp/payment/credit_retry" . myTools::getMobappToken(array_merge(array('token' => $apiToken ), $_GET)) );
13650        $this->render(myTools::getDeviceUrl() . 'Payment/credit_retry');
13651    }
13652
13653    /**
13654     * @api {post} /mobapp/payment/credit_retry_form/:token/:cardToken mobapp_credit_retry_form()
13655     * @apiName mobapp_credit_retry_form
13656     * @apiGroup Payment
13657     * @apiDescription This endpoint is used to process user's credit card retry form.
13658     * 
13659     * @apiParam {String} token User's API token
13660     * @apiParam {String} cardToken User's card token
13661     * 
13662     * @apiBody {Number} payment_gateway_type The type of payment gateway selected
13663     * @apiBody {Object} discountOption The annual discount option data, if available.
13664     * @apiBody {Number} discountOption.user_id The ID of the user.
13665     * @apiBody {Number} discountOption.discount_option_id The ID of the discount option.
13666     * @apiBody {Number} discountOption.status The status of the discount option.
13667     * @apiBody {Number} discountOption.dosh_event The event associated with the discount option.
13668     * @apiBody {Number} discountOption.dosh_status The status of the discount option.
13669     * @apiBody {Object} paymentPlanData The payment plan data for the user. required if paypal payment gateway is selected.
13670     * @apiBody {Number} paymentPlanData.paymentPlanId The ID of the payment plan.
13671     * @apiBody {Number} paymentPlanData.priceId The ID of the price.
13672     * @apiBody {Number} receivablePayment The receivable payment data.
13673     * @apiBody {Number} appreciationReceivable The appreciation payment receivable data.
13674     * @apiBody {Number} liveLessonReceivable The live lesson payment receivable data.
13675     * @apiBody {Number} formType The form type. Sets to 4 for credit retry.
13676     * @apiBody {Number} discounted_amount The total discounted amount from the coupon.
13677     * @apiBody {String} coupon_used The coupon used for the discount.
13678     * @apiBody {String} token The API token.
13679     * @apiBody {Object} ZPaymentFullLogs The payment full logs data.
13680     * @apiBody {String} ZPaymentFullLogs.clientip The client IP address.
13681     * @apiBody {String} ZPaymentFullLogs.telno The default telephone number.
13682     * @apiBody {String} cardToken The card token.
13683     * 
13684     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/paypal_payment_credit_retry_confirm?token={$apiToken} after successful card retry
13685     * 
13686     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if empty payment data and payment plan id or price id is null
13687     * 
13688     * @apiExample Example usage:
13689     * {
13690     *      "payment_gateway_type": 1
13691     *      "discountOption": {
13692     *            "user_id": 12345,
13693     *            "discount_option_id": 67890,
13694     *            "status": 1,
13695     *            "dosh_event": 1
13696     *            "dosh_status": 2
13697     *      },
13698     *      "receivablePayment": 1000,
13699     *      "appreciationReceivable": 500,
13700     *      "liveLessonReceivable": 300,
13701     *      "formType": "payment_credit_retry",
13702     *      "discounted_amount": 200,
13703     *      "coupon_used": "COUPON123",
13704     *      "token": "api_token_12345",
13705     *      "ZPaymentFullLogs": {
13706     *            "clientip": "192.168.1.1",
13707     *            "telno": "1234567890"
13708     *      },
13709     *      "cardToken": "card_token_12345"
13710     * }
13711     * 
13712     * @apiSuccessExample Success Response:
13713     * Redirects to {{ENV}}/mobapp/payment/paypal_payment_credit_retry_confirm?token={$apiToken}
13714     * 
13715     * @apiErrorExample Error Response:
13716     * Redirects to {{ENV}}/mobapp/retrypage
13717     * 
13718     * @apiSampleRequest off
13719     */
13720    public function mobapp_credit_retry_form(){
13721
13722        // - NJ-23812 : reset  
13723        if ($this->Session->read('credit_skip_to_confirmation')){
13724            $this->Session->delete('credit_skip_to_confirmation');
13725        }
13726
13727        $this->blockWithdrawnSapuriToS('mobapp');
13728        $this->disablePageForSapuri('mobapp');
13729        $this->layout = "mobapp";
13730        $urlParams = myTools::getMobappToken($_GET);
13731        $userData = $this->mobappGetUserData(array('logFileName' => 'card_retry', 'formType' => Configure::read('payment_credit_retry'))); // get user data and validate
13732        $apiToken = $this->request->query['token'];
13733        $cardToken = isset($this->request->query['cardToken']) ? $this->request->query['cardToken'] : '';
13734        $userDataArr = $userData['User'];
13735        $corpType = myTools::getCoporateTypeUsingPaymentPlanId($userDataArr['payment_plan_id']);
13736        $corporateLightBool = ($corpType == Configure::read('corporate_type.light'));
13737
13738        // delete payment gateway type memcache
13739        $this->memcache->delete('mobappCreditRetryPaymentGatewayType_' . $apiToken);
13740
13741        // delete payment paypal data memcache
13742        $this->memcache->delete('mobappPaypalPaymentCreditRetryData_' . $apiToken);
13743
13744        // get user active annual discount option
13745        $annualDiscountOptionData = $this->UserDiscountOptionsTerm->getTerm([
13746            'user_id' => $userDataArr['id'],
13747            'discount_option_id' => Configure::read('discount_option.annual.plan_id'),
13748            'status' => 1
13749        ]);
13750
13751        if ($annualDiscountOptionData) {
13752            unset($annualDiscountOptionData['contract_start']);
13753            $annualDiscountOptionData += [
13754                'dosh_event' => Configure::read('discount_option.dosh_event.annual_discount'),
13755                'dosh_status' => Configure::read('discount_option.dosh_status.monthly_discount')
13756            ];
13757        }
13758
13759        // check if there's a post data
13760        if ($this->request->is('post')) {
13761            $data = $this->request->data;
13762
13763            // add annual discount option data
13764            if ($annualDiscountOptionData) {
13765                $data['discountOption'] = $annualDiscountOptionData;
13766            }
13767
13768            // redirect to paypal confirm page if payment gateway selected is paypal
13769            if ($data['payment_gateway_type'] == Configure::read('card_company.paypal')) {
13770                // redirect to retry page if empty payment data and payment plan id or price id is null
13771                if (!$paymentData = $this->getRetryPaymentData($userDataArr, 'card_retry')) {
13772                    return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
13773                }
13774
13775                $data['paymentPlanData'] = $paymentData;
13776                
13777                // add reserve payment receivable
13778                $data['receivablePayment'] = $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id']);
13779
13780                // add appreciation payment receivable
13781                $data['appreciationReceivable'] = $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('appreciation_data.payment_element_type'));
13782
13783                // add live lesson payment receivable
13784                $data['liveLessonReceivable'] = $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('payment_element_type.live'));
13785
13786                $data['formType'] = Configure::read('payment_credit_retry');
13787                
13788                // NJ-47740
13789                $coupon = $this->UsersCouponV1->getCouponUseRequest(array(
13790                    'userId' => $userDataArr['id'],
13791                    'kbn' => Configure::read('coupon_kbn.monthly_settlement')
13792                ));
13793                
13794                if (
13795                    !empty($coupon['result']) && 
13796                    !empty($coupon['grp_id']) && 
13797                    !empty($coupon['amount']) && 
13798                    empty($coupon['has_payment']) // exclude if coupon has payment
13799                ) {
13800                    $data['discounted_amount'] = $coupon['amount'];
13801                    $data['monthlyDiscount'] = $coupon['amount'];
13802                    $data['monthly_grp_id'] = $coupon['grp_id'];
13803                }
13804                // NJ-47740 end
13805
13806                $this->memcache->set(array(
13807                    'key' => 'mobappPaypalPaymentCreditRetryData_' . $apiToken,
13808                    'value' => $data,
13809                    'expire' => 3600 // 1 hour
13810                ));
13811                return $this->redirect(myTools::getUrl() . '/mobapp/payment/paypal_payment_credit_retry_confirm?token=' . $apiToken);
13812            }
13813
13814            // delete payment gateway type memcache
13815            $this->memcache->delete('mobappCreditRetryPaymentGatewayType_' . $apiToken);
13816
13817            // delete payment paypal data memcache
13818            $this->memcache->delete('mobappPaypalPaymentCreditRetryData_' . $apiToken);
13819
13820            $data['token'] = $apiToken;
13821            $data['ZPaymentFullLogs']['clientip'] = Configure::read('ZEUS_clientip');
13822            $data['ZPaymentFullLogs']['telno'] = Configure::read('credit.default_telno');
13823            $data['cardToken'] = $cardToken;
13824
13825            if ($this->memcache->get('mobappUserCreditRetryInfo_'.$apiToken)) {
13826                $this->memcache->delete('mobappUserCreditRetryInfo_'.$apiToken);
13827            }
13828            $this->memcache->set(array(
13829                'key' => 'mobappUserCreditRetryInfo_'.$apiToken,
13830                'value' => $data,
13831                'expire' => 3600
13832            ));
13833
13834            // NJ-25522: Skip confirm page if using 3D secure challenge
13835            $zeus3DSecureChallengeFlg = $this->memcache->get('zeus3DSecureChallengeFlg_' . $userDataArr['id']);
13836
13837            if ($zeus3DSecureChallengeFlg) {
13838                $formType = Configure::read('payment_credit_retry');
13839
13840                $this->Session->write('mobapp_show_welcome_back_modal',true);
13841
13842                $this->unsetTokenMobapp($apiToken, 'cardretry-token-');
13843                $this->zeus_card_process_mobapp(array(
13844                    'data' => $data,
13845                    'form_type' => $formType,
13846                    'referrer' =>  array('controller' => 'Payment', 'action' => 'mobapp_credit_retry', '?' => array('token' => $apiToken)),
13847                    'api_token' => $apiToken
13848                ));
13849            }
13850            return $this->redirect(myTools::getUrl() . '/payment/mobapp_credit_retry_confirm'.$urlParams);
13851        } else {
13852            // delete payment gateway type memcache
13853            $this->memcache->delete('mobappCreditRetryPaymentGatewayType_' . $apiToken);
13854
13855            $this->set('data', $this->memcache->get('mobappUserCreditRetryInfo_'.$apiToken));
13856        }
13857
13858        if (!isset($this->request->query['amount']) || !isset($this->request->query['paymentHash'])) {
13859            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
13860        }
13861        $amount = $this->request->query['amount'];
13862
13863        // NJ-23812 : set suport paypal
13864        $this->setSupportPayPal($userData['User']);
13865        $this->set('userApiToken',$apiToken);
13866        $this->set('paypalUserData',$userData['User']);
13867
13868
13869        //get user data for further processing
13870        $this->set('cardToken', $cardToken);
13871        $this->set('apiToken', $apiToken);
13872        $this->set('error', $this->memcache->get('error-'.$apiToken));
13873        $this->set('title_for_layout', __d('payment','お支払い方法変更'));
13874        $this->set('zeusTransactionFlag', true);
13875        $this->set('amount', $amount);
13876        $this->set('paymentHash', $this->request->query['paymentHash']);
13877        $this->set('discountedAmount', (isset($this->request->query['discountedAmount']) ? $this->request->query['discountedAmount'] : 0));
13878        $this->set('failURLReferer', myTools::getUrl() . "/mobapp/payment/credit_retry_form" . myTools::getMobappToken(array_merge(array('token' => $apiToken ), $_GET)) );
13879        $this->render(myTools::getDeviceUrl() . 'Payment/credit_retry_form');
13880    }
13881
13882    /**
13883     * @api {post} /mobapp/payment/wp_credit_retry/:api_token mobapp_wp-credit_retry()
13884     * @apiName mobapp_wp_credit_retry
13885     * @apiGroup Payment
13886     * @apiDescription this endpoint is used to process the credit card retry for worldpay
13887     * 
13888     * @apiParam {String} api_token user's api token
13889     * 
13890     * @apiBody {Number} cardType card type (0: existing card, 1: new card)
13891     * 
13892     * @apiSuccess {View} Redirect Redirect to {{ENV}}/mobapp_wp_credit_retry_form for new card
13893     * @apiSuccess {View} Rediect Redirect to {{ENV}}/mobapp_wp_credit_retry_confirm?token= for existing card
13894     * 
13895     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage for empty token
13896     * 
13897     * @apiExample {json} Example usage:
13898     * {
13899     *         "cardType": 0
13900     * }
13901     * 
13902     * @apiSuccessExample Success Response New card:
13903     * Redirects to {{ENV}}/mobapp_wp_credit_retry_form for new card
13904     * 
13905     * @apiSuccessExample Success Response Existing card:
13906     * Redirects to {{ENv}}/mobapp_wp_credit_retry_confirm?token= for existing card
13907     * 
13908     * @apiErrorExample Error Response:
13909     * Redirects to {{ENV}}/mobapp/retrypage for empty token
13910     * 
13911     * @apiSampleRequest off
13912     */
13913    public function mobapp_wp_credit_retry() {
13914
13915        if ($this->Session->read('credit_skip_to_confirmation')) {
13916            $this->Session->delete('credit_skip_to_confirmation');
13917        }
13918
13919        $this->blockWithdrawnSapuriToS('mobapp');
13920        $this->disablePageForSapuri('mobapp');
13921        // set variables
13922        $logFileName = 'card_retry';
13923        $formType = Configure::read('payment_credit_retry');
13924        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType));
13925        $userData = $userData['User'];
13926        $this->layout = "mobapp";
13927        $this->response->disableCache();
13928        $apiToken = $userData['api_token'];
13929        $memKey = "credit_retry_{$userData['id']}_{$userData['currency_code']}";
13930        $cardType = $this->memcache->get($memKey);
13931        $cardType = isset($cardType) ? $cardType : 0;
13932
13933        if ($this->request->is('post')) {
13934            $cardType = $this->request->data['cardType'];
13935
13936            // memcache card type value
13937            $this->memcacheCardType(array(
13938                'key' => $memKey,
13939                'value' => $cardType
13940            ));
13941
13942            // redirect to hosted page if using new card ($cardType = 1)
13943            if ($cardType) {
13944                 $this->redirect(myTools::getUrl() . "/mobapp/payment/wp_credit_retry_form".myTools::getMobappToken($_GET));
13945            // redirect to confirm page if using existing card ($cardType = 0)
13946            } else {
13947
13948                // - NJ-23812: write session to skip and auto charge 
13949                $this->Session->write('credit_skip_to_confirmation',true);
13950
13951                $this->redirect(myTools::getUrl() . "/mobapp/payment/wp_credit_retry_confirm?token=$apiToken");
13952            }
13953        }
13954
13955    
13956        // - NJ-23812 : redirect to form
13957        $this->redirect(myTools::getUrl() . "/mobapp/payment/wp_credit_retry_form".myTools::getMobappToken($_GET));
13958
13959        // set view variables
13960        $this->set('cardLogo', myTools::getWorldpayCardLogo($userData['card_brand']));
13961        $this->set('cardBrand', $userData['card_brand']);
13962        $this->set('cardNumber', $userData['card_number']);
13963        $this->set('cardType', $cardType);
13964        $this->set('apiToken', $apiToken);
13965        $this->set('user', $userData);
13966        $this->set('title_for_layout', '再入会');
13967        $this->render(myTools::getDeviceUrl() . 'Payment/wp_credit_retry');
13968    }
13969
13970    /**
13971     * @api {get} /mobapp/payment/wp_credit_retry_form/:api_token mobapp_wp_credit_retry_form()
13972     * @apiName mobapp_wp_credit_retry_form
13973     * @apiGroup Payment
13974     * @apiDescription This endpoint is used to process the credit card retry for worldpay
13975     * 
13976     * @apiParam {String} api_token user's api token
13977     * 
13978     * @apiSuccess {View} Redirect Redirect to {{ENV}}/mobapp/payment/credit_retry_complete?token={$apiToken}&type=credit_retry_complete{$addWelcomeModal} for success
13979     * 
13980     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage for empty token
13981     * 
13982     * @apiSampleRequest off
13983     */
13984    public function mobapp_wp_credit_retry_form() {
13985        $this->blockWithdrawnSapuriToS('mobapp');
13986        $this->disablePageForSapuri('mobapp');
13987        // set variables
13988        $logFileName = 'card_retry';
13989        $formType = Configure::read('payment_credit_retry');
13990        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType));
13991        $apiToken = $userData['User']['api_token'];
13992        $this->layout = "mobapp";
13993        $this->response->disableCache();
13994
13995        // check if allowed aftee
13996        $this->checkAfteeSupported($userData['User']);
13997
13998        // - NJ-23812: start support 
13999        $user = $userData['User'];
14000        $memKey = "credit_retry_{$userData['id']}_{$userData['currency_code']}";
14001        $cardType = $this->memcache->get($memKey);
14002        $cardType = isset($cardType) ? $cardType : 0;
14003
14004        // get error from memcache
14005        $error = $this->memcache->get('card_retry_error_' . $apiToken);
14006
14007        // check and set if there is error
14008        if ($error) {
14009            $this->memcache->delete('card_retry_error_' . $apiToken);
14010            $this->set('error', $error);
14011        }
14012
14013        // - set payment plan details 
14014        $pData = $this->getRetryPaymentData($user, 'card_retry');
14015        $isCardRegistered = (!empty($user['card_brand']) && !empty($user['card_number'])) ? true : false;
14016        $comPlanUser = (isset($user['com_plan_user']) && $user['com_plan_user']) ? $user['com_plan_user'] : false;
14017
14018        // set view variables
14019        $this->set('isCardRegistered',$isCardRegistered);
14020        $this->set('cPlan', $comPlanUser);
14021        $this->set('fAmount', $pData['fAmount']);
14022        $this->set('cardLogo', myTools::getWorldpayCardLogo($user['card_brand']));
14023        $this->set('cardType', $cardType);
14024        $this->set('user', $user);
14025        $this->set('title_for_layout', '再入会');
14026
14027        if ($this->Session->read('mobapp_show_welcome_back_modal')) {
14028            $this->Session->delete('mobapp_show_welcome_back_modal');
14029        }
14030
14031        $addWelcomeModal = "&re_enrolled=1";
14032
14033        // set view vars
14034        $this->set('cardBrand', $user['card_brand']);
14035        $this->set('cardNumber', $user['card_number']);
14036        $this->set('pmtValue', 'payment');
14037        $this->set('apiToken', $apiToken);
14038        $this->set('logFileName', $logFileName);
14039        $this->set('worldpayFlg', true);
14040        $this->set('memKeyError', 'card_retry_error_'.$apiToken);
14041        $this->set('referrer', urlencode(myTools::getUrl()."/mobapp/payment/wp_credit_retry_form?token={$apiToken}"));
14042        $this->set('successUrl', urlencode(myTools::getUrl()."/mobapp/payment/credit_retry_complete?token={$apiToken}&type=credit_retry_complete{$addWelcomeModal}"));
14043        $this->set('formType', $formType);
14044        $this->render(myTools::getDeviceUrl() . 'Payment/wp_credit_retry_form');
14045    }
14046    /**
14047     * @api {post} /mobapp/payment/wp_credit_retry_confirm/:token mobapp_wp_credit_retry_confirm()
14048     * @apiName mobapp_wp_credit_retry_confirm
14049     * @apiGroup Payment
14050     * @apiDescription This endpoint is used to process the credit card retry for worldpay
14051     * 
14052     * @apiParam {String} token user's api token
14053     * 
14054     * @apiSuccess {View} Redirect Redirect to {{ENV}}/mobapp/payment/credit_retry_complete?token=$apiToken&type=credit_retry_complete for success
14055     * 
14056     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage
14057     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/payment/wp_credit_retry?token= for direct payment response is not authorised 
14058     * 
14059     * @apiSuccessExample Success Response:
14060     * Redirects to {{ENV}}/mobapp/payment/credit_retry_complete?token=$apiToken&type=credit_retry_complete
14061     * 
14062     * @apiErrorExample Error Response If direct payment response is not authorised:
14063     * Redirects to {{ENV}}/mobapp/payment/wp_credit_retry?token=
14064     * 
14065     * @apiErrorExample Error Response:
14066     * Redirects to {{ENV}}/mobapp/retrypage
14067     * 
14068     * @apiSampleRequest off
14069     */
14070    public function mobapp_wp_credit_retry_confirm() {
14071        // set variables
14072        $logFileName = 'card_retry';
14073        $formType = Configure::read('payment_credit_retry');
14074        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType));
14075        $this->layout = "mobapp";
14076        $this->response->disableCache();
14077        $amount = $userData['PaymentPlanPrice']['amount'];
14078        $userData = $userData['User'];
14079        $memKey = "credit_retry_{$userId}_{$currencyCode}";
14080        $urlParams = myTools::getMobappToken($_GET);
14081
14082        $userId = $userData['id'];
14083        // redirect to retry page if empty payment data and payment plan id or price id is null
14084        if (!$pData = $this->getRetryPaymentData($userData, $logFileName)) {
14085            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed getRetryPaymentData --> ' . json_encode($userData), 'error');
14086            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
14087        }
14088
14089        $currencyCode = $userData['currency_code'];
14090        $apiToken = $userData['api_token'];
14091        $userData['payment_plan_id'] = $pData['paymentPlanId'];
14092        $userData['price_id'] = $pData['priceId'];
14093        $amount = $pData['amount'];
14094
14095        $currency_before = $userData['currency_code'];
14096        $plan_before = $userData['payment_plan_id'];
14097
14098        $readSkipConfirmation = true;//NJ-23812:force skip view the confirmation page
14099    
14100
14101        if ($this->request->is('post') || $readSkipConfirmation) {
14102            
14103            // NJ-47740
14104            $coupon = $this->UsersCouponV1->getCouponUseRequest(array(
14105                'userId' => $userId,
14106                'kbn' => Configure::read('coupon_kbn.monthly_settlement')
14107            ));
14108            
14109            if (
14110                !empty($coupon['result']) && 
14111                !empty($coupon['grp_id']) && 
14112                !empty($coupon['amount']) && 
14113                empty($coupon['has_payment']) // exclude if coupon has payment
14114            ) {
14115                $amount -= $userData['discounted_amount'] = $coupon['amount'];
14116                $userData['monthlyDiscount'] = $coupon['amount'];
14117                $userData['monthly_grp_id'] = $coupon['grp_id'];
14118            }
14119            // NJ-47740 end
14120
14121            // get reserve payment receivable
14122            $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userId);
14123
14124            // get appreciation lesson payment receivable
14125            $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('appreciation_data.payment_element_type'));
14126
14127            // get live lesson payment receivable
14128            $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.live'));
14129
14130            // add retry payment, receivable payment amount and live lesson payment receivable
14131            $totalAmount = $amount + $receivablePayment + $appreciationReceivable + $liveLessonReceivable;
14132            $orderCode = myTools::generateOrderCode($userId);
14133
14134            $paymentMethodType = myTools::getWPPaymentMethodType($userData['card_brand'], 'payment');
14135            $merchantCode = myTools::getWPMerchantCode($paymentMethodType);
14136            $paymentMethod = explode('_', $paymentMethodType);
14137            $paymentMethod = isset($paymentMethod[0]) ? $paymentMethod[0] : null;
14138            $currencyExponents = Configure::read('worldpay.currency_exponents');
14139            $exponent = $currencyExponents[$currencyCode];
14140
14141            // get total amount with checking currency exponent
14142            $totalAmountArr = myTools::wpGetAmount($exponent, $totalAmount);
14143            $ncAmount = $totalAmountArr['ncAmount'];
14144            $wpAmount = $totalAmountArr['wpAmount'];
14145
14146            $wpData = array(
14147                'cardToken' => $userData['card_token'],
14148                'merchantCode' => $merchantCode,
14149                'paymentHash' => $orderCode,
14150                'wpPaymentAmount' => $wpAmount
14151            );
14152
14153            // set payment amount
14154            $userData['paymentAmount'] = $ncAmount;
14155
14156            // create payment transaction
14157            if (!$pt = $this->createPaymentTransaction($formType, $userData, $wpData)) {
14158                $this->log(__METHOD__ .' Failed to save payment transaction. Params --> ' . json_encode($wpData), $logFileName);
14159                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to save payment transaction. Params --> ' . json_encode($wpData), 'error');
14160                return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
14161            }
14162
14163            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - After save payment transaction. Params --> ' . json_encode($wpData), 'error');
14164
14165            // if aftee payment
14166            if (
14167                $userData['card_company'] == Configure::read('card_company.aftee') ||
14168                ($userData['card_brand'] == "AFTEE" && !empty($userData['aftee_transaction_identifier']))
14169            ) {
14170
14171                // default result
14172                $checkRes = array(
14173                    'OrderCode' => $orderCode,
14174                    'authentication_token' => $userData['card_token'],
14175                    'response' => 'Aftee payment amount is zero',
14176                    'customer' => array(
14177                        'phone_number' =>  $userData['phone_number']
14178                    )
14179                );
14180                $receivableResult = json_encode($checkRes);
14181                $afteeTransactionIdentifier = $userData['aftee_transaction_identifier'];
14182
14183
14184                if ($userData['paymentAmount'] > 0) {
14185
14186                    if (!class_exists('AfteePaymentService')) {
14187                        App::uses('AfteePaymentService','Lib');
14188                    }
14189                    $afteeService = new AfteePaymentService();
14190                    $afteeChecksumData = array(
14191                        'shopItemId' => "AFTEE" . $formType,
14192                        'itemName' => 'CreditRetryUsingExistingCard',
14193                        'itemPrice' => $totalAmount,
14194                        'itemCount' => 1,
14195                        'customerPhoneNumber' => $userData['phone_number'],
14196                        'customerEmail' => $userData['email'],
14197                        'shopTransactionNo' => $orderCode,
14198                        'userID' =>  $userData['id']
14199                    );
14200                    $checksum = $afteeService->generateChecksum($afteeChecksumData, false);
14201                    $afteeData = array(
14202                        'authentication_token' => $userData['card_token'],
14203                        'related_id' => $userData['aftee_transaction_identifier'],
14204                        'checksum' => $checksum['checksum'],
14205                        'shop_transaction_no' => $orderCode,
14206                        'transaction_options' => array(1)
14207                    );
14208
14209                    $afteePaymentData = array_merge($afteeData, $checksum['settlementData']);
14210
14211                    // aftee execute payment
14212                    $receivableResult = $afteeService->directPayment($afteePaymentData);
14213                    $checkRes = json_decode($receivableResult, true);
14214
14215
14216                    if ( isset($checkRes['object']) && $checkRes['object'] == 'transaction') {
14217                        $prPaymentSuccess = true;
14218                    } else if ( !array_key_exists("object", $checkRes) || (isset($checkRes['object']) && $checkRes['object'] == 'error')) {
14219                        $prPaymentSuccess = false;
14220                    }
14221
14222                    $afteeTransactionIdentifier = isset($checkRes['id']) && !empty($checkRes['id']) ? $checkRes['id'] : NULL;
14223                    if (isset($checkRes['related_transaction']) && !empty($checkRes['related_transaction'])) {
14224                        $afteeTransactionIdentifier = $checkRes['related_transaction'];
14225                    }
14226                    $orderCode = isset($checkRes['shop_transaction_no']) && !empty($checkRes['shop_transaction_no']) ? $checkRes['shop_transaction_no'] : NULL;
14227                    $checkRes['OrderCode'] = $orderCode;
14228                }
14229
14230                // process payment data
14231                if ($prPaymentSuccess) {
14232                    // set user model
14233                    $uModel = $this->User;
14234                    $dataSource = $uModel->getDataSource();
14235                    $dataSource->begin();
14236
14237                    $afteeParams = array(
14238                        'data' => $checkRes,
14239                        'ptData' => $pt,
14240                        'logFileName' => $logFileName,
14241                        'dataSource' => $dataSource,
14242                        'amount' => $totalAmount,
14243                        'userData' => $userData,
14244                        'transactionIdentifier' => $afteeTransactionIdentifier,
14245                        'aftee' => 1
14246                    );
14247
14248                    $this->processAfteePayment($afteeParams);
14249                }
14250
14251                // update payment transaction
14252                $updateData = array(
14253                    'id' => $pt['id'],
14254                    'fields' => array(
14255                        'status' => $prPaymentSuccess,
14256                        'response_text' => array('aftee_directPayment_response' => $receivableResult))
14257                );
14258
14259                // update payment transaction
14260                $this->PaymentTransaction->updateAfteePaymentTransaction($updateData);
14261
14262
14263                // redirect to payment_credit_charge with error display if direct payment response is not authorised
14264                if (!$prPaymentSuccess) {
14265                    if (!class_exists('myMemcached')) {
14266                        App::uses('myMemcached', 'Lib');
14267                    }
14268                    $memKeyError = 'card_retry_error_' . $apiToken;
14269                    $memerror = __('トランザクションを完了できません。 もう一度お試しください。');
14270                    $memcached = new myMemcached();
14271                    $memcached->set(array(
14272                        'key' => $memKeyError,
14273                        'value' => $memerror,
14274                        'expire' => 3600 // 1 hour
14275                    ));
14276                    return $this->redirect(myTools::getUrl() . '/mobapp/payment/wp_credit_retry?token='.$apiToken);
14277                }
14278            
14279            // worldpay default
14280            } else {
14281
14282                $wpData = array(
14283                    'merchantCode' => $merchantCode,
14284                    'orderCode' => $orderCode,
14285                    'description' => 'Credit Retry Using Existing Card',
14286                    'currencyCode' => $currencyCode,
14287                    'exponent' => $exponent,
14288                    'amount' => $wpAmount,
14289                    'cardToken' => $userData['card_token'],
14290                    'email' => $userData['email'],
14291                    'authenticatedShopperId' => $userId,
14292                    'xmlName' => 'direct_payment_with_token',
14293                    'shopperIpAddress' => $_SERVER["REMOTE_ADDR"],
14294                    'wpTransactionIdentifier' => $userData['wp_transaction_identifier'],
14295                    'paymentMethod' => $paymentMethod
14296                );
14297
14298                $result = wpPaymentService::directPayment($wpData);
14299
14300                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - directPayment result --> ' . json_encode($result), 'error');
14301
14302                $updateData = array(
14303                    'id' => $pt['id'],
14304                    'fields' => array('response_text' => array('directPayment_response' => $result)),
14305                    'logFileName' => $logFileName
14306                );
14307
14308                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - before updatePaymentTransaction result --> ' . json_encode($updateData), 'error');
14309
14310                // update payment transaction direct response
14311                $this->updatePaymentTransaction($updateData);
14312
14313                // redirect to wp_credit_retry with error display if direct payment response is not authorised
14314                if (!myTools::checkIfWPPaymentResponseIsAuthorised($result)) {
14315                    $params = array(
14316                        'apiToken' => $apiToken,
14317                        'wpResponse' => $result,
14318                        'memKey' => 'card_retry_error_' . $apiToken
14319                    );
14320                    myTools::parseAndSetWPErrorResponse($params);
14321                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - WP Payment not authorised --> ' . json_encode($params), 'error');
14322                    return $this->redirect(myTools::getUrl() . '/mobapp/payment/wp_credit_retry?token='.$apiToken);
14323                }
14324
14325                // - flag manual paying user success
14326                UserTable::saveManualPayingUsersToMemcache($userId);
14327
14328            } 
14329
14330            // delete memcache
14331            if ($this->memcache->get($memKey)) {
14332                $this->memcache->delete($memKey);
14333            }
14334            return $this->redirect(myTools::getUrl() . "/mobapp/payment/credit_retry_complete?token=$apiToken&type=credit_retry_complete");
14335        }
14336
14337        // set view variables
14338        $this->set('cardLogo', myTools::getWorldpayCardLogo($userData['card_brand']));
14339        $this->set('apiToken', $apiToken);
14340        $this->set('cardBrand', $userData['card_brand']);
14341        $this->set('cardNumber', $userData['card_number']);
14342        $this->set('amount', $amount);
14343        $this->render(myTools::getDeviceUrl() . 'Payment/wp_credit_retry_confirm');
14344    }
14345    /**
14346     * @api {post} /payment/mobapp_credit_retry_confirm/:token mobapp_credit_retry_confirm()
14347     * @apiName mobapp_credit_retry_confirm
14348     * @apiGroup Payment
14349     * @apiDescription This endpoint is used to confirm the credit card retry
14350     * 
14351     * @apiParam {String} token user's api token
14352     * 
14353     * @apiSuccess {View} Modal Displays the welcome back modal
14354     * 
14355     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage
14356     * 
14357     * @apiSuccessExample Success Response:
14358     * Displays the welcome back modal
14359     * 
14360     * @apiErrorExample Error Response:
14361     * Redirects to {{ENV}}/mobapp/retrypage
14362     * 
14363     * @apiSampleRequest off
14364     */
14365    public function mobapp_credit_retry_confirm() {
14366        $this->layout = 'mobapp';
14367        $formType = Configure::read('payment_credit_retry');
14368        $userData = $this->mobappGetUserData(array('logFileName' => 'card_retry', 'formType' => $formType)); // get user data and validate
14369        $apiToken = $this->request->query['token'];
14370        $userDataArr = $userData['User'];
14371
14372        // redirect to retry page if data does not exist or expired
14373        if (!$data = $this->memcache->get('mobappUserCreditRetryInfo_'.$apiToken)) {
14374            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.myTools::getMobappToken($_GET));
14375        }
14376
14377        $readSkipConfirmation = true; // NJ:23812: mod skipp confirmation page
14378
14379        if ($this->request->is('post') || $readSkipConfirmation) {
14380            // check if token matches token in session
14381            $checkToken = $this->checkTokenMobapp($apiToken, $data['cardToken'], 'cardretry-token-');
14382
14383            // check if payment hash exist in payment transaction table
14384            if (!$pt = $this->PaymentTransaction->getWPPaymentTransaction($data['ZPaymentFullLogs']['paymentHash'])) {
14385                return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
14386            }
14387
14388            // check if token is true
14389            if ($checkToken) {
14390                $ptpp = json_decode($pt['payment_params'], true);
14391                $data['ZPaymentFullLogs']['money'] = (int)$ptpp['paymentAmount'];
14392                $this->Session->write('mobapp_show_welcome_back_modal',true);
14393                $this->unsetTokenMobapp($apiToken, 'cardretry-token-');
14394                $this->zeus_card_process_mobapp(array(
14395                    'data' => $data,
14396                    'form_type' => $ptpp['formType'],
14397                    'referrer' =>  array('controller' => 'Payment', 'action' => 'mobapp_credit_retry', '?' => array('token' => $apiToken)),
14398                    'api_token' => $apiToken
14399                ));
14400            } else {
14401                // set error message
14402                $this->memcache->set(array(
14403                    'key' => 'card-error-'.$apiToken,
14404                    'value' => 'ERROR : Card validation token mismatch.',
14405                    'expire' => 3600
14406                ));
14407                return $this->redirect(array('controller' => 'Payment', 'action' => 'mobapp_credit_retry', '?' => array('token' => $apiToken)));
14408            }
14409        }
14410
14411        if (isset($data['ZPaymentFullLogs']['cardnumber']) && !empty($data['ZPaymentFullLogs']['cardnumber'])) {
14412            $cardNumberArr = str_split($data['ZPaymentFullLogs']['cardnumber'], 4);
14413            $this->set('cardNumber', end($cardNumberArr));
14414        } else {
14415            $this->getAndSetCardInfo($userData['User']);
14416        }
14417
14418        $corporateUser = false;
14419        $corpType = myTools::getCoporateTypeUsingPaymentPlanId($userDataArr['payment_plan_id']);
14420        if (isset($userDataArr['corporate_id']) && isset($corpType)) {
14421            $corporateUser = true;
14422        }
14423
14424        $this->set('corporateType', $corpType);
14425        $this->set('corporateUser', $corporateUser);
14426        $this->set('data', $data);
14427        $this->set('apiToken', $apiToken);
14428        $this->set('amount', myTools::formatAmount($data['ZPaymentFullLogs']['money']));
14429        $this->render(myTools::getDeviceUrl() . 'Payment/credit_retry_confirm');
14430    }
14431    /**
14432     * @api {get} /mobapp/payment/paypal_payment_credit_retry_confirm/:token mobapp_paypal_payment_credit_retry_confirm()
14433     * @apiName mobapp_paypal_payment_credit_retry_confirm
14434     * @apiGroup Payment
14435     * @apiDescription This endpoint is used to display the paypal payment credit retry confirm page
14436     * 
14437     * @apiParam {String} token user's api token
14438     * 
14439     * @apiSuccess {View} Render Displays the paypal payment credit retry confirm page
14440     * 
14441     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage
14442     * 
14443     * @apiSuccessExample Success Response:
14444     * Displays the paypal payment credit retry confirm page
14445     * 
14446     * @apiErrorExample Error Response:
14447     * Redirects to {{ENV}}/mobapp/retrypage
14448     * 
14449     * @apiSampleRequest off
14450     */
14451    public function mobapp_paypal_credit_retry_confirm() {
14452        $this->layout = 'mobapp';
14453        $logFileName = 'paypal_debug';
14454        $formType = Configure::read('payment_credit_retry');
14455
14456        // get user data and validate
14457        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType));
14458        $user = $userData['User'];
14459        $apiToken = $this->request->query['token'];
14460
14461        // redirect to retry page if data does not exist or expired
14462        if (!$data = $this->memcache->get('mobappPaypalPaymentCreditRetryData_' . $apiToken)) {
14463            $this->log(__METHOD__ . ' credit retry data does not exist or expired. user api token --> ' . json_encode($apiToken), $logFileName);
14464            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage' . myTools::getMobappToken($_GET));
14465        }
14466
14467        $this->set('paypalFlg', true);
14468        $this->set('paypalUserData', $userData['User']);
14469        $this->set('fAmount', myTools::formatAmount($data['ZPaymentFullLogs']['money']));
14470        $this->set('userApiToken', $apiToken);
14471
14472        // set payment gateway type
14473        $this->memcache->set(array(
14474            'key' => 'mobappCreditRetryPaymentGatewayType_' . $apiToken,
14475            'value' => $data['payment_gateway_type'],
14476            'expire' => 3600 // 1 hour
14477        ));
14478
14479        $this->render(myTools::getDeviceUrl() . 'Payment/paypal_credit_retry_confirm');
14480    }
14481    /**
14482     * @api {get} /mobapp/payment/mobapp_paypal_credit_retry_process/:token/:negativeTesting mobapp_paypal_credit_retry_process()
14483     * @apiName mobapp_paypal_credit_retry_process
14484     * @apiGroup Payment
14485     * @apiDescription This endpoint is used to process the paypal payment credit retry
14486     * 
14487     * @apiParam {String} token user's api token
14488     * @apiParam {String} negativeTesting Indicates if negative testing is enabled. 1 for enabled, 0 for disabled
14489     * 
14490     * @apiSuccess {View} Redirect Redirect to {{ENV}}/mobapp/payment/credit_retry_complete?token=$apiToken&type=credit_retry_complete for success
14491     * 
14492     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/payment/credit_retry?token=$apiToken for negative testing or payment failed
14493     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage for empty token
14494     * 
14495     * @apiSuccessExample Success Response:
14496     * Redirects to {{ENV}}/mobapp/payment/credit_retry_complete?token=$apiToken&type=credit_retry_complete
14497     * 
14498     * @apiErrorExample Error Response If negative testing or payment failed:
14499     * Redirects to {{ENV}}/mobapp/payment/credit_retry?token=$apiToken
14500     * 
14501     * @apiErrorExample Error Response If empty token:
14502     * Redirects to {{ENV}}/mobapp/payment/credit_retry?token=$apiToken
14503     * 
14504     * @apiSampleRequest off
14505     */
14506    public function mobapp_paypal_credit_retry_process() {
14507        $this->autoRender = false;
14508        $this->layout = false;
14509
14510        $logFileName = 'paypal_debug';
14511        $formType = Configure::read('payment_credit_retry');
14512
14513        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType));
14514        $get = $this->request->query;
14515        $apiToken = $get['token'];
14516        $memKey = 'mobappPaypalPaymentCreditRetryData_' . $apiToken;
14517        $res = array('success' => false);
14518
14519        // redirect to retry page if data does not exist or expired
14520        if (!$data = $this->memcache->get($memKey)) {
14521            $this->log(__METHOD__ . ' credit retry data does not exist or expired. user api token --> ' . json_encode($apiToken), $logFileName);
14522            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage' . myTools::getMobappToken($_GET));
14523        }
14524
14525        // NJ-44815: Resolve mobapp paypal issue coupon discount amount not applied
14526        if (
14527            isset($data['ZPaymentFullLogs']['discounted_amount']) && $data['ZPaymentFullLogs']['discounted_amount'] &&
14528            isset($data['monthlyDiscount']) && $data['monthlyDiscount'] &&
14529            isset($data['monthly_grp_id']) && $data['monthly_grp_id']
14530        ) {
14531            $data['discountedAmount'] = $data['ZPaymentFullLogs']['discounted_amount'];
14532        }
14533
14534        if ((isset($get['negativeTesting']) && $get['negativeTesting']) || !$this->processPayPalPayment($data, $userData['User'])) {
14535            // set the memcache error
14536            $this->memcache->set(array(
14537                'key' => 'card-error-'.$apiToken,
14538                'value' => __("Error : 決済失敗"),
14539                'expire' => 3600 // 1 hour
14540            ));
14541
14542            return $this->redirect('/mobapp/payment/credit_retry?token='.$apiToken);
14543        }
14544
14545        $memKey = 'mobappCreditRetryPaymentGatewayType_' . $apiToken;
14546
14547        // delete memcache payment gateway type
14548        if ($this->memcache->get($memKey)) {
14549            $this->memcache->delete($memKey);
14550        }
14551
14552        UserTable::saveManualPayingUsersToMemcache($userData['User']['id']);
14553        $this->memcache->delete('mobappUserCreditRetryInfo_'.$apiToken);
14554
14555        return $this->redirect(array('controller' => 'Payment', 'action' => 'mobapp_credit_retry_complete', '?' => array('token' => $apiToken, 'type' => 'credit_retry_complete')));
14556    }
14557
14558    /**
14559     * @api {get} /mobapp/payment/credit_register_trial_notice/:token mobapp_credit_register_trial_notice()
14560     * @apiName mobapp_credit_register_trial_notice
14561     * @apiGroup Payment
14562     * @apiDescription This endpoint is used to display the credit card register trial notice page
14563     * 
14564     * @apiParam {String} token user's api token
14565     * 
14566     * @apiSuccess {View} Render Displays the credit card register trial notice page
14567     * 
14568     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage
14569     * 
14570     * @apiSuccessExample Success Response:
14571     * Displays the credit card register trial notice page
14572     * 
14573     * @apiErrorExample Error Response:
14574     * Redirects to {{ENV}}/mobapp/retrypage
14575     * 
14576     * @apiSampleRequest off
14577     */
14578    public function mobapp_credit_register_trial_notice() {
14579        // set variables
14580        $this->layout = 'mobapp';
14581        $logFileName = 'card_reregister';
14582        $formType = Configure::read('payment_credit_authentication');
14583        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType)); // get user data and validate
14584        $userData = $userData['User'];
14585        $userObj = new UserTable($userData);
14586        $apiToken = $this->request->query['token'];
14587
14588        $this->set('token', $apiToken);
14589        $this->set('user', $userData);
14590        $this->set('userObj', $userObj);
14591        $this->render(myTools::getDeviceUrl() . 'Payment/credit_register_trial_notice');
14592    }
14593
14594    /**
14595     * @api {get} /mobapp/payment/credit_register/:token mobapp_credit_register()
14596     * @apiName mobapp_credit_register
14597     * @apiGroup Payment
14598     * @apiDescription This endpoint is used to display the credit card register page
14599     * 
14600     * @apiParam {String} token user's api token
14601     * 
14602     * @apiSuccess {View} Render Displays the credit card register page
14603     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/wp_credit_register if currency is not JPY
14604     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/credit_charge if user is corporate user
14605     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/register/sms_authentication if user has not verified phone number
14606     * 
14607     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage
14608     * 
14609     * @apiSuccessExample Success Response:
14610     * Displays the credit card register page
14611     * 
14612     * @apiSuccessExample Success Response If currency is not JPY:
14613     * Redirects to {{ENV}}/mobapp/payment/wp_credit_register
14614     * 
14615     * @apiSuccessExample Success Response If user is corporate user:
14616     * Redirects to {{ENV}}/mobapp/payment/credit_charge
14617     * 
14618     * @apiSuccessExample Success Response If user has not verified phone number:
14619     * Redirects to {{ENV}}/mobapp/register/sms_authentication
14620     * 
14621     * @apiErrorExample Error Response:
14622     * Redirects to {{ENV}}/mobapp/retrypage
14623     * 
14624     * @apiSampleRequest off
14625     */
14626    public function mobapp_credit_register() {
14627
14628        // - NJ-23812: reset 
14629        if ($this->Session->read('credit_skip_to_confirmation')) {
14630            $this->Session->delete('credit_skip_to_confirmation');
14631        }
14632
14633        //- NJ-27262 : check private page from chocotto
14634        $this->set('enableChocottoPlan', $this->Cookie->read('chocotto_lp'));
14635
14636        $this->response->disableCache();
14637        $this->blockWithdrawnSapuriToS('mobapp');
14638        $this->disablePageForSapuri('mobapp');
14639
14640        // NJ-37156: Cancel plan change to lite plan if user has family added (mobapp)
14641        $hasFamily = json_decode($this->User->checkFamily($this->Session->read('Auth.User.id')), true);
14642        if($hasFamily['status'] != 'normal') {
14643            return $this->redirect(myTools::getUrl().'/mobapp/retrypage'.myTools::getMobappToken($_GET));
14644        }
14645
14646        // set variables
14647        $this->layout = 'mobapp';
14648        $urlParams = myTools::getMobappToken($_GET);
14649        $logFileName = 'card_reregister';
14650        $formType = Configure::read('payment_credit_authentication');
14651        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType)); // get user data and validate
14652        $userData = $userData['User'];
14653        $apiToken = $this->request->query['token'];
14654
14655
14656        // delete payment gateway type memcache
14657        $this->memcache->delete('mobappCreditReregisterPaymentGatewayType_' . $apiToken);
14658        
14659        // redirect to worldpay if not zuespay user (currency != JPY)
14660        if ($userData['currency_code'] != Configure::read('currency_jpy')) {
14661            $this->memcache->delete('success-auth'.$apiToken);
14662            return $this->redirect(myTools::getUrl() . '/mobapp/payment/wp_credit_register'.$urlParams);
14663        }
14664
14665        // no free trial for corporate users
14666        if (!empty($userData['corporate_id'])) {
14667            return $this->redirect(myTools::getUrl() . '/mobapp/payment/credit_charge'.$urlParams);
14668        }
14669
14670        // if has complimentary code
14671        if (!empty($userData['complimentary_code'])) {
14672            $this->set('cPlan', true);
14673        } else {
14674            // NC-3914
14675            $this->getAndSetCardInfo($userData);
14676        }
14677
14678        // get free trial payment data
14679        $freeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
14680            'currencyCode' => $userData['currency_code'],
14681            'paymentPlanId' => Configure::read('payment_plans.free_trial'),
14682            'logFileName' => $logFileName
14683        ));
14684
14685        if (!$freeTrialData) {
14686            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.myTools::getMobappToken($_GET));
14687        }
14688
14689        $user = new UserTable($userData);
14690        $membershipTypes = UserTable::getEngMembershipTypeData();
14691        $membershipTypeIndex = $user->getMembershipTypeIndex();
14692
14693        $userData['price_id'] = $freeTrialData['priceId'];
14694        $userData['payment_plan_id'] = $freeTrialData['paymentPlanId'];
14695        $userData['paymentAmount'] = $freeTrialData['amount'];
14696        $userData['statusBefore'] = $membershipTypes[$membershipTypeIndex];
14697        $userData['statusAfter'] = $membershipTypes[2];
14698
14699        // set transaction error to 1 if failed to create payment transaction
14700        if (!$pt = $this->createPaymentTransaction($formType, $userData)) {
14701            $this->set('transactionError', 1);
14702        }
14703
14704        // clear previously set card tokens and set new card token
14705        $this->unsetTokenMobapp($apiToken, 'card-register-');
14706        $cardToken = md5(uniqid(rand(), true));
14707        $this->memcache->set(array(
14708            'key' => 'card-register-'.$apiToken,
14709            'value' => $cardToken,
14710            'expire' => 3600
14711        ));
14712
14713        // get and delete error from memcache
14714        if ($error = $this->memcache->get('card-error-'.$apiToken)) {
14715            $this->memcache->delete('card-error-'.$apiToken);
14716        }
14717        
14718        // - NJ-23812 : delete previous paypal data
14719        $this->memcache->delete('mobappPaypalPaymentCreditRegisterData_' . $apiToken);
14720
14721        $sessionPaypalParams = array(
14722            'token' => isset($token) ? $token : "",
14723            'payment_gateway_type' => Configure::read('card_company.paypal'),
14724            'ZPaymentFullLogs' => array(
14725                'money' => $freeTrialData['amount'],
14726                'paymentHash' => $pt['payment_hash'],
14727                'discounted_amount' => (isset($discountedAmount)) ? $discountedAmount : 0
14728            ),
14729            'paymentPlanData' => $freeTrialData,
14730            'formType' => $formType
14731        );
14732
14733        $this->memcache->set(array(
14734            'key' => 'mobappPaypalPaymentCreditRegisterData_' . $apiToken,
14735            'value' => $sessionPaypalParams,
14736            'expire' => 3600 // 1 hour
14737        ));
14738
14739        // get monthly price for premium
14740        $pDataDisplay = $this->PaymentPlanPrice->getPaymentData(array(
14741            'currencyCode' => $userData['currency_code'],
14742            'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
14743            'logFileName' => 'card_reregister'
14744        ));
14745
14746        $currencyData = $this->Currency->getSymbolAndPosition($userData['currency_code']);
14747    
14748        // set view display
14749        $this->set('monthlyPrice', myTools::formatAmount($pDataDisplay['amount']));
14750        $this->set('monthylyPriceNoTax',myTools::formatAmount($pDataDisplay['amountConstTaxDeducted']));
14751        $this->set('monthlyPriceSymbol',myTools::getCurrencySymbol($userData['currency_code']));
14752
14753        // - set paypal support 
14754        $this->set('userApiToken', $apiToken); // for paypal_reregister.php (using different variable name)
14755        $this->setSupportPayPal($userData);
14756
14757        $this->set('title_for_layout', __d('register','7日間無料トライアル'));
14758
14759        // NJ-18780 : set view support for lite plan
14760        $this->setLitePaymentInfoView($userData,false,true);
14761
14762        // NJ-30828: set view to display user's paypal email
14763        $this->setPaypalUser($userData);
14764        $annualDiscountOptionData = $this->DiscountOptionsPrice->getPaymentData(['currencyCode' => $userData['currency_code'], 'discountOptionId' => Configure::read('discount_option.annual.plan_id')]);
14765        $annualDiscountOptionAmount = $annualDiscountOptionData ? $annualDiscountOptionData['amount'] : 0;
14766        $monthlyPriceWithAnnualDiscount = $pDataDisplay['amount'] - $annualDiscountOptionAmount;
14767        $monthlyPriceWithAnnualDiscountNoTax = $monthlyPriceWithAnnualDiscount / Configure::read('added_tax_percentage');
14768        $monthlyPriceWithAnnualDiscountNoTax = round($monthlyPriceWithAnnualDiscountNoTax);
14769
14770        $this->set('enableAnnualDiscountOption', $annualDiscountOptionData ? true : false);
14771        $this->set('annualDiscountOptionAmount', myTools::formatAmount($annualDiscountOptionAmount));
14772        $this->set('monthlyPriceWithAnnualDiscount', myTools::formatAmount($monthlyPriceWithAnnualDiscount));
14773        $this->set('monthlyPriceWithAnnualDiscountNoTax', myTools::formatAmount($monthlyPriceWithAnnualDiscountNoTax));
14774
14775        #chocotto plan data
14776        $chocottoPlanData = $this->PaymentPlanPrice->getPaymentData(array(
14777            'currencyCode' => $userData['currency_code'],
14778            'paymentPlanId' => Configure::read('payment_plans.chocotto_plan'),
14779            'logFileName' => $logFileName ?? 'card_register'
14780        ));
14781
14782        // - set chocotto plan price
14783        $this->set('chocottoMonthlyPrice',$chocottoPlanData['fAmount']);
14784        $this->set('chocottoMonthlyPriceNoTax', myTools::formatAmount($chocottoPlanData['amountConstTaxDeducted']));
14785
14786        //- NJ-27262 : check private page from chocotto
14787        $this->set('enableChocottoPlan', $this->Cookie->read('chocotto_lp'));
14788
14789        // set view variables
14790        $this->set('data', $this->memcache->get('mobappUserCreditRegisterInfo_'.$apiToken));
14791        $this->set('error', $error);
14792        $this->set('amount', $freeTrialData['amount']);
14793        $this->set('apiToken', $apiToken);
14794        $this->set('cardToken', $cardToken);
14795        $this->set('zeusTransactionFlag', true);
14796        $this->set('paymentHash', $pt['payment_hash']);
14797        $this->set('title_for_layout', __d('register','7日間無料トライアル'));
14798        $this->set('failURLReferer', myTools::getUrl() . "/mobapp/payment/credit_register" .myTools::getMobappToken(array_merge(array('token' => $apiToken ), $_GET)) );
14799        $this->render(myTools::getDeviceUrl() . 'Payment/credit_register');
14800
14801    }
14802
14803    /**
14804     * @api {post} /mobapp/payment/credit_register_form/:token/:cardToken/:paymentHash mobapp_credit_register_form()
14805     * @apiName mobapp_credit_register_form
14806     * @apiGroup Payment
14807     * @apiDescription This endpoint is used to process the credit card register form
14808     * 
14809     * @apiParam {String} token user's api token
14810     * @apiParam {String} cardToken user's card token
14811     * @apiParam {String} paymentHash user's payment hash
14812     * 
14813     * @apiBody {Number} payment_gateway_type The type of payment gateway selected
14814     * @apiBody {Object} discountOption The annual discount option data, if available.
14815     * @apiBody {Number} discountOption.user_id The ID of the user.
14816     * @apiBody {Number} discountOption.discount_option_id The ID of the discount option.
14817     * @apiBody {Number} discountOption.status The status of the discount option.
14818     * @apiBody {Number} discountOption.dosh_event The event associated with the discount option.
14819     * @apiBody {Number} discountOption.dosh_status The status of the discount option.
14820     * @apiBody {Object} paymentPlanData The payment plan data for the user. required if paypal payment gateway is selected.
14821     * @apiBody {Number} paymentPlanData.paymentPlanId The ID of the payment plan.
14822     * @apiBody {Number} paymentPlanData.priceId The ID of the price.
14823     * @apiBody {Number} receivablePayment The receivable payment data.
14824     * @apiBody {Number} appreciationReceivable The appreciation payment receivable data.
14825     * @apiBody {Number} liveLessonReceivable The live lesson payment receivable data.
14826     * @apiBody {Number} formType The form type. Sets to 4 for credit retry.
14827     * @apiBody {Number} discounted_amount The total discounted amount from the coupon.
14828     * @apiBody {String} coupon_used The coupon used for the discount.
14829     * @apiBody {String} token The API token.
14830     * @apiBody {Object} ZPaymentFullLogs The payment log data.
14831     * @apiBody {String} ZPaymentFullLogs.clientip The client IP address.
14832     * @apiBody {String} ZPaymentFullLogs.telno The default telephone number.
14833     * @apiBody {String} cardToken The card token.
14834     * 
14835     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/paypal_payment_credit_register_confirm?token= for paypal payment gateway
14836     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/credit_register_confirm for success
14837     * 
14838     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/payment/credit_register for error or failure
14839     * 
14840     * @apiExample Example usage:
14841     * {
14842     *      "payment_gateway_type": 1
14843     *      "discountOption": {
14844     *            "user_id": 12345,
14845     *            "discount_option_id": 67890,
14846     *            "status": 1,
14847     *            "dosh_event": 1
14848     *            "dosh_status": 2
14849     *      },
14850     *      "receivablePayment": 1000,
14851     *      "appreciationReceivable": 500,
14852     *      "liveLessonReceivable": 300,
14853     *      "formType": "payment_credit_retry",
14854     *      "discounted_amount": 200,
14855     *      "coupon_used": "COUPON123",
14856     *      "token": "api_token_12345",
14857     *      "ZPaymentFullLogs": {
14858     *            "clientip": "192.168.1.1",
14859     *            "telno": "1234567890"
14860     *      },
14861     *      "cardToken": "card_token_12345"
14862     * }
14863     * 
14864     * @apiSuccessExample Success Response For Paypal Payment Gateway:
14865     * Redirects to {{ENV}}/mobapp/payment/paypal_payment_credit_register_confirm?token=
14866     * 
14867     * @apiSuccessExample Success Response:
14868     * Redirects to {{ENV}}/mobapp/payment/credit_register_confirm
14869     * 
14870     * @apiErrorExample Error Response:
14871     * Redirects to {{ENV}}/mobapp/payment/credit_register
14872     * 
14873     * @apiSampleRequest off
14874     */
14875    public function mobapp_credit_register_form() {
14876
14877        if ($this->Session->read('credit_skip_to_confirmation')) {
14878            $this->Session->delete('credit_skip_to_confirmation');
14879        }
14880
14881        $this->blockWithdrawnSapuriToS('mobapp');
14882        $this->disablePageForSapuri('mobapp');
14883        $this->layout = 'mobapp';
14884        $urlParams = myTools::getMobappToken($_GET);
14885        $logFileName = 'card_retry';
14886        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => Configure::read('payment_credit_authentication'))); // get user data and validate
14887        $apiToken = $this->request->query['token'];
14888        $cardToken = isset($this->request->query['cardToken']) ? $this->request->query['cardToken'] : '';
14889
14890        $appVersion = $this->request->query['appVersion'];
14891        $deviceType = $this->request->query['deviceType'];
14892        $this->set('appVersion', $appVersion);
14893        $this->set('deviceType', $deviceType);
14894
14895        // get free trial payment data
14896        $freeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
14897            'currencyCode' => $userData['User']['currency_code'],
14898            'paymentPlanId' => Configure::read('payment_plans.free_trial'),
14899            'logFileName' => $logFileName
14900        ));
14901
14902        if (!$freeTrialData) {
14903            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
14904        }
14905        // Set Data on form load
14906        $data['paymentPlanData'] = $freeTrialData;
14907        $this->memcache->set(array(
14908            'key' => 'mobappPaypalPaymentCreditRegisterData_' . $apiToken,
14909            'value' => $data,
14910            'expire' => 3600 // 1 hour
14911        ));
14912        // check if post data
14913        if ($this->request->is('post')) {
14914            $data = $this->request->data;
14915
14916            // redirect to paypal confirm page if payment gateway selected is paypal
14917            if ($data['payment_gateway_type'] == Configure::read('card_company.paypal')) {
14918                $data['paymentPlanData'] = $freeTrialData;
14919                $this->memcache->set(array(
14920                    'key' => 'mobappPaypalPaymentCreditRegisterData_' . $apiToken,
14921                    'value' => $data,
14922                    'expire' => 3600 // 1 hour
14923                ));
14924                return $this->redirect(myTools::getUrl() . '/mobapp/payment/paypal_payment_credit_register_confirm?token=' . $apiToken);
14925            }
14926
14927            // delete payment gateway type memcache
14928            $this->memcache->delete('mobappCreditReregisterPaymentGatewayType_' . $apiToken);
14929
14930            $data['cardToken'] = $cardToken;
14931            $data['ZPaymentFullLogs']['telno'] = Configure::read('credit.default_telno');
14932            $data['ZPaymentFullLogs']['clientip'] = Configure::read('ZEUS_clientip');
14933            $data['cardToken'] = $cardToken;
14934
14935            // - check if user selected lite plan (1 = lite , 0 = premium)
14936            $paymentPlanType = (isset($data['ZPaymentFullLogs']['payment_plan_type'])) ? (int) $data['ZPaymentFullLogs']['payment_plan_type'] : 0;
14937
14938            if ($paymentPlanType == Configure::read('register_plan_types.light')) {
14939                $userTable = new UserTable($userData['User']);
14940                $_membershipTypes = UserTable::getEngMembershipTypeData();
14941                $_membershipTypeIndex = $userTable->getMembershipTypeIndex();
14942
14943                // - fetch the lite payment plan 
14944                $litefreeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
14945                    'currencyCode' => $userData['User']['currency_code'],
14946                    'paymentPlanId' => Configure::read('payment_plans.light_plan_free'),
14947                    'logFileName' => 'card_reregister'
14948                ));
14949
14950                // - change the price id and payment plan 
14951                $_user = $userData['User'];
14952
14953                $_user['price_id'] = $litefreeTrialData['priceId'];
14954                $_user['payment_plan_id'] = $litefreeTrialData['paymentPlanId'];
14955                $_user['paymentAmount'] = $litefreeTrialData['amount'];
14956                $_user['statusBefore'] = $membershipTypes[$membershipTypeIndex];
14957                $_user['statusAfter'] = $membershipTypes[36]; // - light plan free
14958
14959                $formType = myTools::getLitePlanUserFormType($litefreeTrialData['paymentPlanId']);
14960
14961                // set transaction 
14962                $pt = $this->createPaymentTransaction($formType, $_user);
14963
14964                if ($pt) {
14965                    // - update the payment hash
14966                    $data['ZPaymentFullLogs']['paymentHash'] =    $pt['payment_hash'];
14967                }
14968
14969                // - set data to lite planuser 
14970                $data['isLitePlanUser'] = 1;
14971
14972            //- chocotto plan
14973            } elseif ($paymentPlanType == Configure::read('register_plan_types.chocotto')) {
14974                $userTable = new UserTable($userData['User']);
14975                $_membershipTypes = UserTable::getEngMembershipTypeData();
14976                $_membershipTypeIndex = $userTable->getMembershipTypeIndex();
14977
14978                // - fetch the chocotto payment plan 
14979                $chocottoFreeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
14980                    'currencyCode' => $userData['User']['currency_code'],
14981                    'paymentPlanId' => Configure::read('payment_plans.free_trial_chocotto'),
14982                    'logFileName' => 'card_reregister'
14983                ));
14984
14985                // - change the price id and payment plan 
14986                $_user = $userData['User'];
14987
14988                $_user['price_id'] = $chocottoFreeTrialData['priceId'];
14989                $_user['payment_plan_id'] = $chocottoFreeTrialData['paymentPlanId'];
14990                $_user['paymentAmount'] = $chocottoFreeTrialData['amount'];
14991                $_user['statusBefore'] = $membershipTypes[$membershipTypeIndex];
14992                $_user['statusAfter'] = $membershipTypes[Configure::read('membership_type_chocotto_plan_free')];
14993
14994                $formType = myTools::getChocottoPlanUserFormType($chocottoFreeTrialData['paymentPlanId']);
14995
14996                // set transaction 
14997                $pt = $this->createPaymentTransaction($formType, $_user);
14998
14999                if ($pt) {
15000                    // - update the payment hash
15001                    $data['ZPaymentFullLogs']['paymentHash'] =    $pt['payment_hash'];
15002                }
15003
15004                // - set data to chocotto plan 
15005                $data['isChocottoPlanUser'] = 1;
15006
15007            // if annual discount option
15008            } elseif ($paymentPlanType == Configure::read('register_plan_types.premium_with_annual_discount_option')) {
15009                $annualDiscountOptionData = $this->DiscountOptionsPrice->getPaymentData(['currencyCode' => $userData['User']['currency_code'], 'discountOptionId' => Configure::read('discount_option.annual.plan_id')]);
15010
15011                // redirect to credit page if annual discount option does not exist or is not enabled
15012                if (!$annualDiscountOptionData) {
15013                    return $this->redirect('/');
15014                }
15015
15016                // change amount to 0 since this is a subscription
15017                $annualDiscountOptionData['amount'] = 0;
15018                $annualDiscountOptionData += [
15019                    'dosh_event' => Configure::read('discount_option.dosh_event.annual_discount'),
15020                    'dosh_status' => Configure::read('discount_option.dosh_status.subscription'),
15021                    'option_after_name' => 'Annual Discount Option',
15022                    'option_type' => 3
15023                ];
15024
15025                // update payment transaction (add annual discount option data)
15026                $this->PaymentTransaction->updatePaymentParams(array('paymentHash' => $data['ZPaymentFullLogs']['paymentHash'], 'updateData' => ['discountOption' => $annualDiscountOptionData]));
15027
15028                $data['discountOption'] = $annualDiscountOptionData;
15029            }
15030
15031            if ($this->memcache->get('mobappUserCreditRegisterInfo_'.$apiToken)) {
15032                $this->memcache->delete('mobappUserCreditRegisterInfo_'.$apiToken);
15033            }
15034            $this->memcache->set(array(
15035                'key' => 'mobappUserCreditRegisterInfo_'.$apiToken,
15036                'value' => $data,
15037                'expire' => 3600
15038            ));
15039
15040            //NJ-25522: Skip confirm page if using 3D secure challenge
15041            //NJ-13482 Skip Confirmation Page for New Enrollment
15042            $zeus3DSecureChallengeFlg = $this->memcache->get('zeus3DSecureChallengeFlg_' . $userData['User']['id']);
15043            if (isset($userData['User']['id']) && (!$this->isForTrialReenrollment($userData['User']['id']) || $zeus3DSecureChallengeFlg)) {
15044                $formType = Configure::read('payment_credit_authentication');
15045                $checkToken = $this->checkTokenMobapp($apiToken, $data['cardToken'], 'card-register-');
15046                $this->Session->write('mobapp_show_welcome_back_modal',true);
15047                // check if token is true
15048                if ($checkToken) {
15049                    $this->zeus_card_process_mobapp(array(
15050                        'data' => $data,
15051                        'form_type' => $formType,
15052                        'referrer' =>  array('controller' => 'Payment', 'action' => 'mobapp_credit_register', '?' => array('token' => $apiToken)),
15053                        'api_token' => $apiToken,
15054                        'card_token' => $data['cardToken']
15055                    ));
15056                }
15057            }
15058            return $this->redirect(myTools::getUrl() . '/payment/mobapp_credit_register_confirm'.myTools::getMobappToken(array_merge(array('token' => $apiToken ), $_GET)) );
15059
15060        } else {
15061            // delete payment gateway type memcache
15062            $this->memcache->delete('mobappCreditReregisterPaymentGatewayType_' . $apiToken);
15063
15064            $this->set('data', $this->memcache->get('mobappUserCreditRegisterInfo_'.$apiToken));
15065        }
15066
15067        // check if param payment hash does not exist
15068        if (!isset($this->request->query['paymentHash'])) {
15069            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
15070        }
15071
15072        $paymentHash = $this->request->query['paymentHash'];
15073
15074        // check if payment hash exist in payment transaction table
15075        if (!$this->PaymentTransaction->getWPPaymentTransaction($paymentHash)) {
15076            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
15077        }
15078
15079        // get free trial payment data
15080        $freeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
15081            'currencyCode' => $userData['User']['currency_code'],
15082            'paymentPlanId' => Configure::read('payment_plans.free_trial'),
15083            'logFileName' => $logFileName
15084        ));
15085
15086        if (!$freeTrialData) {
15087            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
15088        }
15089
15090        // set view variables
15091        $this->setSupportPayPal($userData);
15092        $this->set('userApiToken', $apiToken); // for paypal_reregister.php (using different variable name)
15093        $this->set('apiToken', $apiToken);
15094        $this->set('cardToken', $cardToken);
15095        $this->set('zeusTransactionFlag', true);
15096        $this->set('amount', $freeTrialData['amount']);
15097        $this->set('paymentHash', $paymentHash);
15098        $this->set('title_for_layout', '再入会');
15099        $this->set('failURLReferer', myTools::getUrl() . "/mobapp/payment/credit_register".myTools::getMobappToken(array_merge(array('token' => $apiToken ), $_GET)) );
15100        $this->render(myTools::getDeviceUrl() . 'Payment/credit_register_form_new');
15101    }
15102
15103    /**
15104     * @api {post} /payment/credit_register_form sp_credit_register_form()
15105     * @apiName sp_credit_register_form
15106     * @apiGroup Payment
15107     * @apiDescription This endpoint is used to display and process the credit card register form in sp version
15108     * 
15109     * @apiBody {Number} payment_gateway_type The type of payment gateway selected by the user.
15110     * @apiBody {Object} ZPaymentFullLogs Contains additional payment log information.
15111     * @apiBody {String} ZPaymentFullLogs.clientip The client's IP address.
15112     * @apiBody {String} ZPaymentFullLogs.telno The default telephone number.
15113     * @apiBody {Object} [paymentPlanData] Contains payment plan data for the free trial. Used for paypal payment.
15114     * @apiBody {String} [paymentPlanData.currencyCode] The currency code for the payment plan.
15115     * @apiBody {Number} [paymentPlanData.paymentPlanId] The ID of the payment plan.
15116     * @apiBody {Number} [paymentPlanData.amount] The amount for the payment plan.
15117     * 
15118     * @apiSuccess {View} Render Displays the credit card register form
15119     * @apiSuccess {View} Redirect Redirects to {{ENV}}/payment/paypal_payment_credit_register_confirm for paypal payment
15120     * @apiSuccess {View} Redirect Redirects to {{ENV}}/payment/payment_credit_register_confirm for credit card payment
15121     * 
15122     * @apiError {View} Redirect Redirects to {{ENV}}/ if free trial data is missing
15123     * 
15124     * @apiExample {json} Example usage:
15125     * {
15126     *         "payment_gateway_type": 1,
15127     *         "ZPaymentFullLogs": {
15128     *             "clientip": "192.168.1.1"
15129     *             "telno": "1234567890"
15130     *         }
15131     * }
15132     * 
15133     * @apiSuccessExample Success Response:
15134     * Displays the credit card register form
15135     * 
15136     * @apiSuccessExample Success Response If paypal payment:
15137     * Redirects to {{ENV}}/payment/paypal_payment_credit_register_confirm
15138     * 
15139     * @apiSuccessExample Success Response If credit card payment:
15140     * Redirects to {{ENV}}/payment/payment_credit_register_confirm
15141     * 
15142     * @apiErrorExample Error Response:
15143     * Redirects to {{ENV}}/
15144     * 
15145     * @apiSampleRequest off
15146     */
15147    public function sp_credit_register_form() {
15148        $this->blockWithdrawnSapuriToS();
15149        $this->disablePageForSapuri();
15150        $this->checkUser(Configure::read('payment_credit_authentication'));
15151        $logFileName = 'card_reregister';
15152        $userData = $this->sharedUserData;
15153        $apiToken = $userData['User']['api_token'];
15154        // get free trial payment data
15155        $freeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
15156            'currencyCode' => $userData['User']['currency_code'],
15157            'paymentPlanId' => Configure::read('payment_plans.free_trial'),
15158            'logFileName' => $logFileName
15159        ));
15160
15161        if (!$freeTrialData) {
15162            return $this->redirect(myTools::getUrl());
15163        }
15164
15165        if ($this->sharedUserData['User']['currency_code'] == Configure::read('default.user_currency')) {
15166            $this->zeus_credit_register();
15167        // redirect to wp
15168        }
15169        // check if post data
15170        if ($this->request->is('post')) {
15171            $data = $this->request->data;
15172            // redirect to paypal confirm page if payment gateway selected is paypal
15173            if ($data['payment_gateway_type'] == Configure::read('card_company.paypal')) {
15174                $data['paymentPlanData'] = $freeTrialData;
15175                $this->Session->write('paypalPaymentCreditRegisterData', $data);
15176                return $this->redirect(myTools::getUrl() . '/payment/paypal_payment_credit_register_confirm');
15177            }
15178            // delete payment gateway type memcache
15179            $this->memcache->delete('creditReregisterPaymentGatewayType_' . $apiToken);
15180
15181            $data['ZPaymentFullLogs']['clientip'] = Configure::read('ZEUS_clientip');
15182            $data['ZPaymentFullLogs']['telno'] = Configure::read('credit.default_telno');
15183
15184            if ($this->Session->read('PaymentCreditRegisterInfo')) {
15185                $this->Session->delete('PaymentCreditRegisterInfo');
15186            }
15187            $this->Session->write('PaymentCreditRegisterInfo', $data);
15188            return $this->redirect(myTools::getUrl() . '/payment/payment_credit_register_confirm');
15189        } else {
15190            // delete payment gateway type memcache
15191            $data = $this->Session->read('PaymentCreditRegisterInfo');
15192            $this->set('data', $data);
15193        }
15194
15195        // set view variables
15196        $this->set('apiToken', $apiToken);
15197        $this->set('zeusTransactionFlag', true);
15198        $this->set('amount', $freeTrialData['amount']);
15199        // $this->set('paymentHash', $paymentHash);
15200        $renderParam = array(
15201            'forceMobile' => true,
15202            'this' => $this,
15203            'spView' => '/Mobile/Payment/payment_credit_register_form',
15204            'layout' => 'mobile'
15205        );
15206
15207        myTools::render($renderParam);
15208    }
15209    /**
15210     * @api {post} /mobapp/payment/credit_register_confirm/:token mobapp_credit_register_confirm()
15211     * @apiName mobapp_credit_register_confirm
15212     * @apiGroup Payment
15213     * @apiDescription This endpoint is used to process the credit card register confirmation
15214     * 
15215     * @apiParam {String} token user's api token
15216     * 
15217     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/notice_to_user for credit card authentication
15218     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/close for Force Charge, Lite Credit Paid, Chocotto Monthly Payment, Chocotto Force Charge
15219     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/store/card_register_complete for Credit Card Change
15220     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/credit_retry_complete for Credit Card Retry
15221     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/close for Individual Corporate Standard, Premium, Light Membership
15222     * 
15223     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage for user not found
15224     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/payment/failure_settlement if on maintenance period
15225     * 
15226     * @apiSuccessExample Success Response If credit card authentication:
15227     * Redirects to {{ENV}}/mobapp/payment/notice_to_user
15228     * 
15229     * @apiSuccessExample Success Response If Force Charge, Lite Credit Paid, Chocotto Monthly Payment, Chocotto Force Charge:
15230     * Redirects to {{ENV}}/mobapp/close
15231     * 
15232     * @apiSuccessExample Success Response If Credit Card Change:
15233     * Redirects to {{ENV}}/mobapp/store/card_register_complete
15234     * 
15235     * @apiSuccessExample Success Response If Credit Card Retry:
15236     * Redirects to {{ENV}}/mobapp/payment/credit_retry_complete
15237     * 
15238     * @apiSuccessExample Success Response If Individual Corporate Standard, Premium, Light Membership:
15239     * Redirects to {{ENV}}/mobapp/close
15240     * 
15241     * @apiErrorExample Error Response If user not found:
15242     * Redirects to {{ENV}}/mobapp/retrypage
15243     * 
15244     * @apiErrorExample Error Response If on maintenance period:
15245     * Redirects to {{ENV}}/mobapp/payment/failure_settlement
15246     * 
15247     * @apiSampleRequest off
15248     */
15249    public function mobapp_credit_register_confirm() {
15250        $this->layout = 'mobapp';
15251        $formType = Configure::read('payment_credit_authentication');
15252        $userData = $this->mobappGetUserData(array('logFileName' => 'card_reregister', 'formType' => $formType)); // get user data and validate
15253        $apiToken = $this->request->query['token'];
15254
15255        // redirect to retry page if data does not exist or expired
15256        if (!$data = $this->memcache->get('mobappUserCreditRegisterInfo_'.$apiToken)) {
15257            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.myTools::getMobappToken($_GET));
15258        }
15259
15260        $readSkipConfirmation = true; // skip the confirmation page
15261
15262        if ($this->request->is('post') || $readSkipConfirmation) {
15263            // check if token matches token in session
15264            $checkToken = $this->checkTokenMobapp($apiToken, $data['cardToken'], 'card-register-');
15265
15266            // check if token is true
15267            if ($checkToken) {
15268                $this->Session->write('mobapp_show_welcome_back_modal',true);
15269                $this->zeus_card_process_mobapp(array(
15270                    'data' => $data,
15271                    'form_type' => $formType,
15272                    'referrer' =>  array('controller' => 'Payment', 'action' => 'mobapp_credit_register', '?' => array('token' => $apiToken)),
15273                    'api_token' => $apiToken,
15274                    'card_token' => $data['cardToken']
15275                ));
15276            }
15277        }
15278
15279        if (isset($data['ZPaymentFullLogs']['cardnumber']) && !empty($data['ZPaymentFullLogs']['cardnumber'])) {
15280            $this->set('cardNumber', end(str_split($data['ZPaymentFullLogs']['cardnumber'], 4)));
15281        } else {
15282            $this->getAndSetCardInfo($userData['User']);
15283        }
15284
15285        $this->set('title_for_layout', __d('register','無料トライアル'));
15286        $this->set('data', $data);
15287        $this->set('apiToken', $apiToken);
15288        $this->render(myTools::getDeviceUrl() . 'Payment/credit_register_confirm');
15289    }
15290    /**
15291     * @api {get} /mobapp/payment/paypal_payment_credit_register_confirm/:token mobapp_paypal_credit_register_confirm()
15292     * @apiName mobapp_paypal_credit_register_confirm
15293     * @apiGroup Payment
15294     * @apiDescription This endpoint is used to display the paypal credit card register confirmation page
15295     * 
15296     * @apiParam {String} token user's api token
15297     * 
15298     * @apiSuccess {View} Render Renders the paypal credit card register confirmation page
15299     * 
15300     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if data does not exist or expired
15301     * 
15302     * @apiSuccessExample Success Response:
15303     * Render the paypal credit card register confirmation page
15304     * 
15305     * @apiErrorExample Error Response:
15306     * Redirects to {{ENV}}/mobapp/retrypage
15307     * 
15308     * @apiSampleRequest off
15309     */
15310    public function mobapp_paypal_credit_register_confirm() {
15311        $this->layout = 'mobapp';
15312        $logFileName = 'paypal_debug';
15313
15314        // get user data and validate
15315        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => Configure::read('payment_credit_authentication')));
15316        $apiToken = $this->request->query['token'];
15317
15318        // redirect to retry page if data does not exist or expired
15319        if (!$data = $this->memcache->get('mobappPaypalPaymentCreditRegisterData_' . $apiToken)) {
15320            $this->log(__METHOD__ . ' credit register data does not exist or expired. user api token --> ' . json_encode($apiToken), $logFileName);
15321            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage' . myTools::getMobappToken($_GET));
15322        }
15323
15324        // set payment gateway type
15325        $this->memcache->set(array(
15326            'key' => 'mobappCreditReregisterPaymentGatewayType_' . $apiToken,
15327            'value' => $data['payment_gateway_type'],
15328            'expire' => 3600 // 1 hour
15329        ));
15330
15331        $this->set('title_for_layout', __d('register','無料トライアル'));
15332        $this->set('paypalFlg', true); // use for modal loader
15333        $this->set('userApiToken', $apiToken);
15334        $this->render(myTools::getDeviceUrl() . 'Payment/paypal_credit_register_confirm');
15335    }
15336    /**
15337     * @api {get} /mobapp/payment/paypal_payment_credit_register_process/:token/:negativeTesting mobapp_paypal_credit_register_process()
15338     * @apiName mobapp_paypal_credit_register_process
15339     * @apiGroup Payment
15340     * @apiDescription This endpoint is used to process the paypal credit card register
15341     * 
15342     * @apiParam {String} token user's api token
15343     * @apiParam {String} negativeTesting negative testing flag 1 = true, 0 = false
15344     * 
15345     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/notice_to_user if success
15346     * 
15347     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if data does not exist or expired
15348     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/payment/credit_register if negative testing
15349     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if light plan data does not exist
15350     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if chocotto plan data does not exist
15351     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/payment/credit_register if paypal settlement fails
15352     * 
15353     * @apiSuccessExample Success Response:
15354     * Redirects to {{ENV}}/mobapp/payment/notice_to_user
15355     * 
15356     * @apiErrorExample Error Response If data does not exist or expired:
15357     * Redirects to {{ENV}}/mobapp/retrypage
15358     * 
15359     * @apiErrorExample Error Response If negative testing:
15360     * Redirects to {{ENV}}/mobapp/payment/credit_register
15361     * 
15362     * @apiErrorExample Error Response If light plan data does not exist:
15363     * Redirects to {{ENV}}/mobapp/retrypage
15364     * 
15365     * @apiErrorExample Error Response If chocotto plan data does not exist:
15366     * Redirects to {{ENV}}/mobapp/retrypage
15367     * 
15368     * @apiErrorExample Error Response If paypal settlement fails:
15369     * Redirects to {{ENV}}/mobapp/payment/credit_register
15370     * 
15371     * @apiSampleRequest off
15372     */
15373    public function mobapp_paypal_credit_register_process() {
15374        $this->autoRender = false;
15375        $this->layout = false;
15376        $logFileName = 'paypal_debug';
15377
15378        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => Configure::read('payment_credit_authentication')));
15379        $get = $this->request->query;
15380        $apiToken = $get['token'];
15381        $memKey = 'mobappPaypalPaymentCreditRegisterData_' . $apiToken;
15382
15383        //- NJ-27262 clear from landing page
15384        $this->Cookie->delete('chocotto_lp');
15385
15386        // negative testing
15387        if (isset($get['negativeTesting']) && $get['negativeTesting']) {
15388            // set the memcache error
15389            $this->memcache->set(array(
15390                'key' => 'card-error-'.$apiToken,
15391                'value' => __("Error : 決済失敗"),
15392                'expire' => 3600 // 1 hour
15393            ));
15394
15395            $memKey = 'paypalBillingAgreementData_' . $apiToken;
15396
15397            // delete memcache billing agreement data
15398            if ($this->memcache->get($memKey)) {
15399                $this->memcache->delete($memKey);
15400            }
15401
15402            return $this->redirect(myTools::getUrl() . "/mobapp/payment/credit_register?token=" . $apiToken);
15403        }
15404
15405        // redirect to retry page if data does not exist or expired
15406        if (!$data = $this->memcache->get($memKey)) {
15407            $this->log(__METHOD__ . ' credit register data does not exist or expired. user api token --> ' . json_encode($apiToken), $logFileName);
15408            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage' . myTools::getMobappToken($_GET));
15409        }
15410
15411        $data['formType'] = Configure::read('payment_credit_authentication');
15412
15413        $userTable = new UserTable($userData['User']);
15414        $membershipTypes = UserTable::getEngMembershipTypeData();
15415        $membershipTypeIndex = $userTable->getMembershipTypeIndex();
15416
15417        // - NJ-18780 : init var
15418        $paymentPlanType = (isset($get['payment_plan_type']) && $get['payment_plan_type'] ) ? $get['payment_plan_type'] : 0;
15419
15420
15421        $userData['User']['statusBefore'] = $membershipTypes[$membershipTypeIndex];
15422        $userData['User']['statusAfter'] = $membershipTypes[2];
15423
15424        if ($paymentPlanType == Configure::read('register_plan_types.light')) {
15425            
15426            // - fetch the lite payment plan 
15427            $litefreeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
15428                'currencyCode' => $userData['User']['currency_code'],
15429                'paymentPlanId' => Configure::read('payment_plans.light_plan_free'),
15430                'logFileName' => 'card_reregister'
15431            ));
15432
15433            if (!$litefreeTrialData) {
15434
15435                // delete memcache paypal payment credit register data
15436                $this->memcache->delete($memKey);
15437
15438                $this->log(__METHOD__ . ' payment plan data does not exist or expired. user api token --> ' . json_encode($apiToken), $logFileName);
15439                return $this->redirect(myTools::getUrl() . '/mobapp/retrypage' . myTools::getMobappToken($_GET));
15440            }
15441
15442            // - update the light price id 
15443            $lightPlanPriceId = $litefreeTrialData['priceId'];
15444
15445            // - NJ-18780 : set  light free membership type 
15446            $normalLightFreeMemtype = Configure::read('membership_type_lightplan_free');
15447
15448            $user['statusAfter'] = $membershipTypes[$normalLightFreeMemtype];// update the status after to lite plan free
15449
15450            // - set update data 
15451            $data['paymentPlanData'] = $litefreeTrialData;// set to update the plan use
15452
15453            // update the form type 
15454            $data['formType'] = myTools::getLitePlanUserFormType(Configure::read('payment_plans.light_plan_free'));
15455
15456        // if annual discount option
15457        } elseif ($paymentPlanType == Configure::read('register_plan_types.premium_with_annual_discount_option')) {
15458            $annualDiscountOptionData = $this->DiscountOptionsPrice->getPaymentData(['currencyCode' => $userData['User']['currency_code'], 'discountOptionId' => Configure::read('discount_option.annual.plan_id')]);
15459
15460            // redirect to credit page if annual discount option does not exist or is not enabled
15461            if (!$annualDiscountOptionData) {
15462                return $this->redirect('/');
15463            }
15464
15465            // change amount to 0 since this is a subscription
15466            $annualDiscountOptionData['amount'] = 0;
15467
15468            // update payment transaction (add annual discount option data)
15469            $this->PaymentTransaction->updatePaymentParams(array('paymentHash' => $data['ZPaymentFullLogs']['paymentHash'], 'updateData' => ['annualDiscountOption' => $annualDiscountOptionData]));
15470
15471            $data['discountOption'] = $annualDiscountOptionData;
15472
15473        //- NJ-27262 : new chocotto plan
15474        } elseif ($paymentPlanType == Configure::read('register_plan_types.chocotto')) {
15475            
15476            // - fetch the chocotto payment plan 
15477            $chocottofreeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
15478                'currencyCode' => $userData['User']['currency_code'],
15479                'paymentPlanId' => Configure::read('payment_plans.free_trial_chocotto'),
15480                'logFileName' => 'card_reregister'
15481            ));
15482
15483            if (!$chocottofreeTrialData) {
15484
15485                // delete memcache paypal payment credit register data
15486                $this->memcache->delete($memKey);
15487
15488                $this->log(__METHOD__ . ' payment plan data does not exist or expired. user api token --> ' . json_encode($apiToken), $logFileName);
15489                return $this->redirect(myTools::getUrl() . '/mobapp/retrypage' . myTools::getMobappToken($_GET));
15490            }
15491
15492            // - update the light price id 
15493            $chocottoPlanPriceId = $chocottofreeTrialData['priceId'];
15494
15495            // - NJ-27262 : set  chocotto free membership type 
15496            $chocottoFreeMemtype = Configure::read('membership_type_chocotto_plan_free');
15497
15498            $user['statusAfter'] = $membershipTypes[$chocottoFreeMemtype];// update the status after to chocotto plan free
15499
15500            // - set update data 
15501            $data['paymentPlanData'] = $chocottofreeTrialData;// set to update the plan use
15502
15503            // update the form type 
15504            $data['formType'] = myTools::getChocottoPlanUserFormType(Configure::read('payment_plans.free_trial_chocotto'));
15505        }
15506
15507        $this->Session->write('mobapp_show_welcome_back_modal',true);
15508
15509        // process paypal settlement
15510        $result = $this->paypalSaveBillingAgreement($data, $userData['User']);
15511
15512        // delete memcache paypal payment credit register data
15513        $this->memcache->delete($memKey);
15514
15515        // redirect to reregister page if result is false
15516        if (!$result['success']) {
15517            // set the memcache error
15518            $this->memcache->set(array(
15519                'key' => 'card-error-'.$apiToken,
15520                'value' => __("Error : 決済失敗"),
15521                'expire' => 3600 // 1 hour
15522            ));
15523
15524            $memKey = 'paypalBillingAgreementData_' . $apiToken;
15525
15526            // delete memcache billing agreement data
15527            if ($this->memcache->get($memKey)) {
15528                $this->memcache->delete($memKey);
15529            }
15530
15531            $result['status'] = 0;
15532
15533            // update payment transaction
15534            $this->PaymentTransaction->paypalUpdatePaymentTransaction($result);
15535            return $this->redirect(myTools::getUrl() . "/mobapp/payment/credit_register?token=" . $apiToken);
15536        }
15537
15538        // send registration completion email
15539        App::uses('myMailer','Lib');
15540        $mailId = Configure::read('site_in_mail.student_registration_complete');
15541        myMailer::sendTemplateMail($mailId, $userData['User']['email'], $userData['User'], array(), 'User');
15542
15543        $memKey = 'mobappCreditReregisterPaymentGatewayType_' . $apiToken;
15544
15545        // delete memcache payment gateway type
15546        if ($this->memcache->get($memKey)) {
15547            $this->memcache->delete($memKey);
15548        }
15549
15550        // redirect to notice to user page
15551        $this->Session->write('reenroll_native_option', true);
15552        return $this->redirect(array('controller' => 'Payment', 'action' => 'mobapp_credit_register_notice_to_user', '?' => array('token' => $apiToken)));
15553    }
15554
15555    /**
15556     * @api {get} /mobapp/payment/notice_to_user/:token/:cardType mobapp_credit_register_notice_to_user()
15557     * @apiName mobapp_credit_register_notice_to_user
15558     * @apiGroup Payment
15559     * @apiDescription This endpoint is used to display the notice to user page
15560     * 
15561     * @apiParam {String} token user's api token
15562     * @apiParam {String} cardType user's card type
15563     * 
15564     * @apiSuccess {View} Render Renders the notice_to_user page
15565     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/close for Chocotto Plan
15566     * 
15567     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage for user not found / amount does not exist / complimentary code does not exist
15568     * 
15569     * @apiSuccessExample Success Response:
15570     * Renders the notice_to_user page
15571     * 
15572     * @apiSuccessExample Success Response If Chocotto Plan:
15573     * Redirects to {{ENV}}/mobapp/clos
15574     * 
15575     * @apiErrorExample Error Response If user not found / amount does not exist / complimentary code does not exist:
15576     * Redirects to {{ENV}}/mobapp/retrypage
15577     * 
15578     * @apiSampleRequest off
15579     */
15580    public function mobapp_credit_register_notice_to_user(){
15581        $this->layout = 'mobapp';
15582        $urlParams = myTools::getMobappToken($_GET);
15583
15584        // redirect to retry page if param token is not set
15585        if (!isset($this->request->query['token']) || empty($this->request->query['token'])) {
15586            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
15587        }
15588
15589        // get api token
15590        $apiToken = $this->request->query['token']; 
15591        $userParams = array(
15592            'fields' => array(
15593                'User.id',
15594                'User.currency_code',
15595                'User.card_company',
15596                'User.timezone_id',
15597                'User.next_charge_date',
15598                'User.complimentary_code',
15599                'User.payment_plan_id',
15600                'User.native_language2'
15601        ),
15602            'apiToken' => $apiToken
15603        );
15604
15605        // redirect to retry page if user does not exist
15606        if (!$userData = $this->User->getWPMobappUserData($userParams)) {
15607            $this->log(__METHOD__ . ' User api token does not exist. User params --> ' . json_encode($userParams), $logFileName);
15608            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.myTools::getMobappToken($_GET));
15609        }
15610
15611        //- chocotto plan
15612        if (in_array(
15613            $userData['User']['payment_plan_id'],
15614            [
15615                Configure::read('payment_plans.free_trial_chocotto'),
15616                Configure::read('payment_plans.chocotto_plan')
15617            ]
15618        )) {
15619            return $this->redirect('/mobapp/close'.myTools::getMobappToken($_GET)."&type=chocotto");
15620        }
15621
15622        // get monthly price
15623        $amount = $this->PaymentPlanPrice->getMonthlyPrice(array(
15624            'currencyCode' => $userData['User']['currency_code'],
15625            'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
15626            'numberFormatFlg' => true
15627        ));
15628
15629        // redirect to retry page if amount does not exist
15630        if (!isset($amount)) {
15631            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.myTools::getMobappToken($_GET));
15632        }
15633
15634        // if not paypal user
15635        if ($userData['User']['card_company'] != Configure::read('card_company.paypal')) {
15636            // read cache card token
15637            $cacheCardToken = $this->memcache->get('card-register-'.$apiToken);
15638            $cardToken = isset($this->request->query['cardToken']) ? $this->request->query['cardToken'] : null;
15639
15640            if ((!$cacheCardToken || !$cardToken) && ($cacheCardToken !== $cardToken) && !isset($this->request->query['wp'])) {
15641                //set error
15642                $this->memcache->set(array(
15643                    'key' => 'card-error-'.$apiToken,
15644                    'value' => 'ERROR : Card validation token mismatch.',
15645                    'expire' => 3600
15646                    ));
15647                //redirect to select credit cards
15648                return $this->redirect(array(
15649                    'controller' => 'Payment',
15650                    'action' => 'mobapp_credit_register',
15651                    '?' => array('token' => $apiToken)
15652                    ));
15653            }
15654
15655            $this->memcache->delete('card-register-'.$apiToken);
15656        }
15657
15658        //get device platform
15659        $platform = myTools::mobappDetectPlatform();
15660
15661        //update user platform
15662        $this->User->updateUserPlatform($userData['User']['id'], $platform);
15663        
15664        //NJ-13482 Rerenced from notice_to_user::notice_to_user
15665        $userCurrencycode = isset($userData['User']['currency_code']) ? $userData['User']['currency_code'] : Configure::read('default.currency_code');
15666        $monthlyPrice = $this->PaymentPlanPrice->getMonthlyPrice(array(
15667            'currencyCode' => $userCurrencycode,
15668            'paymentPlanId' => Configure::read('payment_plans.premium_plan')
15669        ));
15670
15671        $currencyData = ClassRegistry::init('Currency')->getSymbolAndPosition($userCurrencycode);
15672        $monthlyPriceSymbol =  myTools::getCurrencySymbol($userCurrencycode);
15673        $this->set('monthlyPrice', myTools::addPriceSymbol(myTools::formatAmount($monthlyPrice), $currencyData['symbol'], $currencyData['prefix_suffix_flg']));
15674        $this->set('monthlyPriceSymbol', $monthlyPriceSymbol);
15675
15676        $_timeDiff = $this->Timezone->getTimeDiff(
15677            array(
15678                'id' => $userData['User']['timezone_id']
15679            )
15680        );
15681        $timeDiff = $_timeDiff * 60;
15682        $nextSettlementDate = '';
15683
15684        if(!empty($userData['User']['next_charge_date']) && $userData['User']['next_charge_date'] != 0) {
15685            $date = date('Y-m-d H:59', strtotime($userData['User']['next_charge_date'] . '-1 hour'));
15686        } else {
15687            $date = $this->User->getFirstNextChargeDate();
15688            if($userData['User']['card_company'] == Configure::read('card_company.zeus')) {
15689                $date = date('Y-m-d H:i:s', strtotime($date . '-1 minute'));
15690            } else {
15691                $date = date('Y-m-d ', strtotime($date)) . date('H:59');
15692            }
15693        }
15694
15695        // NC-7459
15696        if (
15697            $userData['User']['complimentary_code']
15698            && isset($userData['User']['payment_plan_id'])
15699            && $userData['User']['payment_plan_id'] != Configure::read('payment_plans.free_trial') // except if user is registering to free trial from complimentary
15700        ) { // @NOTE double check
15701            $ccData = $this->ComplimentaryCode->useReplica()->find('first', array(
15702            'fields' => array('available_days'),
15703            'conditions' => array('code' => $userData['User']['complimentary_code'])
15704            ));
15705
15706            if (!$ccData) {
15707                $this->log(__METHOD__.' complimentary code does not exist.' . json_encode($userData), 'card_registration');
15708                return $this->redirect(myTools::getUrl().'/mobapp/retrypage'.myTools::getMobappToken($_GET));
15709            }
15710            $availableDays = $ccData['ComplimentaryCode']['available_days'] ? $ccData['ComplimentaryCode']['available_days'] - 1 : 0;
15711            $date = date('Y-m-d H:i:s', strtotime('+'.$availableDays.' days'));
15712        }
15713        // convert to user time
15714        $userDate = TimezoneTable::computeTimeToUser(array(
15715            'time' => strtotime($date),
15716            'timestamp' => $timeDiff,
15717            'format' => 'Y-m-d H:i:s'
15718        ));
15719
15720        $weekdate = date('w', strtotime($userDate));
15721        if ($userData['User']['complimentary_code']) {
15722            $time = date('23:59', strtotime($userDate));
15723        } else {
15724            $time = date('H:i', strtotime($userDate));
15725        }
15726
15727
15728        $year = date('Y', strtotime($userDate));
15729        $month = $userData['User']['native_language2'] == 'en' ? date('M', strtotime($userDate)) : date('m', strtotime($userDate));
15730        $day = date('d', strtotime($userDate));
15731
15732        if ( in_array($userData['User']['native_language2'], Configure::read('main_supported_language')) ) {
15733
15734            if ($userData['User']['native_language2'] != Configure::read('default.user_language') ) {
15735                if ($userData['User']['native_language2'] == 'en') {
15736                    $format = 'm d, Y';
15737                } else {
15738                    $format = __d('account','Y年m月d日');
15739                }
15740            } else {
15741                $format = 'Y 年 m 月 d 日';
15742            }
15743
15744            $pattern = array();
15745            $replace = array();
15746
15747            $pattern[0] = '/Y/';
15748            $pattern[1] = '/m/';
15749            $pattern[2] = '/d/';
15750
15751            $replace[0] = $year;
15752            $replace[1] = $month;
15753            $replace[2] = $day;
15754
15755
15756            $nextSettlementDate = preg_replace($pattern, $replace, $format);
15757
15758        } else {
15759            $nextSettlementDate = date('F j, Y', strtotime($userDate));
15760        }
15761
15762        
15763        if (!$this->globalLanguage && $userData['User']['native_language2'] != 'en') {
15764            $week = array(__dx('account','week',"日"), __dx('account','week',"月"), __dx('account','week',"火"), __dx('account','week',"水"), __dx('account','week',"木"), __dx('account','week',"金"), __dx('account','week',"土"));
15765            $nextSettlementDate .= ' ('.$week[$weekdate].')';
15766        }
15767
15768        $userInfo = $this->User->getUserDataByApiToken($apiToken);
15769        $userId = $userInfo['User']['id'];
15770
15771        // - get bonus coins on registration
15772        $receiveBonus = UsersPointTable::checkIfUserReceiveBonusUponRegister($userId);
15773        if (!$receiveBonus && empty($userInfo['User']['complimentary_code'])) {
15774            UsersPointTable::giveBonusCoins(['userId' => $userId, 'triggerNo' => 1]);
15775        }
15776
15777        # NJ-18780 - lite plan native option setting ->
15778        $settingName = Configure::read('setting_names.native_plan_display_setting');
15779        $settingData = ClassRegistry::init('SettingOption')->getOptions($settingName);
15780
15781        $userObj = new UserTable($userInfo);
15782        $userMemberShipTypeIndexInt = $userObj->getMembershipTypeIndex();
15783
15784        $continueURL = '/mobapp/payment/native_plan'.myTools::getMobappToken($_GET);
15785
15786        if(empty($userData['User']['corporate_id']) && empty($userData['User']['studysapuri_id']) && !empty($settingData)) {
15787            if (isset($settingData['display_on_membership']) && !in_array($userMemberShipTypeIndexInt, $settingData['display_on_membership']) ||
15788                (isset($settingData['display_currency_codes']) && !in_array($userObj->currency_code, $settingData['display_currency_codes']))
15789            ) {
15790                $continueURL = '/mobapp/close'.myTools::getMobappToken($_GET)."&type=sign_up";
15791            }
15792        }
15793
15794        $this->set('continueTo', $continueURL);
15795        # NJ-18780 - lite native option setting  <-
15796
15797        //set variable
15798        $this->set('apiToken', $apiToken);
15799        $this->set('amount', $amount);
15800        $this->set('nextSettlementDate', $nextSettlementDate. ' ' . $time);
15801        $this->set('userLanguage', isset($userData['User']['native_language2']) ? $userData['User']['native_language2'] : Configure::read('default.user_language'));
15802        $this->render(myTools::getDeviceUrl() . 'Payment/notice_to_user');
15803    }
15804
15805    /**
15806     * @api {get} /mobapp/payment/native_plan/:token mobapp_credit_register_native_plan()
15807     * @apiName mobapp_credit_register_native_plan
15808     * @apiGroup Payment
15809     * @apiDescription This endpoint is used to display the native plan page
15810     * 
15811     * @apiParam {String} token user's api token
15812     * 
15813     * @apiSuccess {View} Render Renders the native_plan page
15814     * 
15815     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/close for user not found
15816     * 
15817     * @apiSuccessExample Success Response:
15818     * Renders the native_plan page
15819     * 
15820     * @apiErrorExample Error Response If user not found:
15821     * Redirects to {{ENV}}/mobapp/close
15822     * 
15823     * @apiSampleRequest off
15824     */
15825    public function mobapp_credit_register_native_plan() {
15826
15827        $checkSessionWelcomeModal = $this->Session->read('mobapp_show_welcome_back_modal');
15828        if ($checkSessionWelcomeModal) {
15829            $this->Session->delete('mobapp_show_welcome_back_modal');
15830        }
15831
15832        $this->set('checkSessionWelcomeModal',$checkSessionWelcomeModal);
15833
15834        $this->layout = 'mobapp';
15835        $token = !empty($this->request->query['token']) ? $this->request->query['token'] : "";
15836        $userInfo = ClassRegistry::init("User")->find("first", array("conditions" => array("User.api_token"=> $token), 'recursive' => -1));
15837        $userData = new UserTable($userInfo["User"]);
15838
15839        if (time() < strtotime(Configure::read('native_option_cashback_campaign.period.end'))) {
15840            $isCashBackCampaign = true;
15841        } else {
15842            $isCashBackCampaign = false;
15843        }
15844        
15845        $monthlyPriceSymbol =  myTools::getCurrencySymbol($userData->currency_code);
15846        $getNativeOptionPaymentCharge = $this->NativeOption->getNativeOptionPaymentCharge(
15847            array(
15848                'daily_calculation' => true,
15849                'half_price' => $isCashBackCampaign,
15850                'user_id' => $userData->id,
15851            )   
15852        );
15853        $pData = $getNativeOptionPaymentCharge;
15854        $optionData = $pData['native_option_data'];
15855        $amount = isset($optionData['amount']) ? myTools::formatAmount($optionData['amount']) : 0;
15856        $symbol = isset($optionData['symbol']) ? $optionData['symbol'] : '';
15857        $monthly_price = isset($pData['monthly_price']) ? myTools::formatAmount($pData['monthly_price']) : 0;
15858        $num1 = str_replace(',', '', $monthly_price);
15859        $num2 = str_replace(',', '', $amount);
15860        $total = $num1 + $num2;
15861        $formatTotal = 0;
15862        if (!empty(strpos($total, "."))) {
15863            $formatTotal = number_format($total, 2);
15864        } else {
15865            $formatTotal = number_format($total);
15866        }
15867
15868
15869        // -----  NJ-23812 start support for native plan charge --------
15870        $request_data = $this->request->query;
15871        $unli_option_type = isset($request_data['unli_option']) ? $request_data['unli_option'] : Configure::read('native_speaker.options.all_you_can_eat');
15872
15873        $optionAmount = 0;
15874        $initialAmount = 0;
15875        $nativeOptionName = '';
15876        $currencySymbol = '';
15877        $prefix_suffix_flg = '';
15878        $logFileName = 'native_option_debug';
15879        $currency = $this->currency;
15880        
15881
15882        if ($userData) {
15883            // - ini reason
15884            $reason = 2;
15885
15886            //If user membership type is invalid
15887            if (!in_array($userData->getMembershipTypeIndex(), Configure::read('native_speaker.valid_memberships')) && !in_array($userData->getMembershipTypeIndex(), Configure::read('corporate_company_payment.native_option_allowed_user'))){
15888                   if (isset($userData->payment_plan_id)) {
15889                        $corpType = myTools::getCoporateTypeUsingPaymentPlanId($userData->payment_plan_id);
15890                        // light or limited
15891                        if (in_array($corpType, array(3,4))) {
15892                            $reason = 4;
15893                        } else {
15894                            $reason = 3;
15895                        }
15896                    }
15897                    return $this->redirect(myTools::getUrl() . '/mobapp/close' . myTools::getMobappToken($_GET)).'&type=sign_up';
15898            }
15899
15900            $registerOption = $this->Session->read('reenroll_native_option') ? 1 : 0;
15901
15902        }
15903
15904
15905        if($unli_option_type == Configure::read('native_speaker.options.all_you_can_eat')) {
15906            if (time() < strtotime(Configure::read('native_option_cashback_campaign.period.end'))) {
15907                $isCashBackCampaign = true;
15908            } else {
15909                $isCashBackCampaign = false;
15910            }
15911            $getNativeOptionPaymentCharge = $this->NativeOption->getNativeOptionPaymentCharge(
15912                array(
15913                    'daily_calculation' => true,
15914                    'half_price' => $isCashBackCampaign,
15915                    'user_id' => $userData->id,
15916                    'option_type' => Configure::read('native_speaker.options.all_you_can_eat')
15917                )   
15918            );
15919            if ($getNativeOptionPaymentCharge) {
15920                if (!$this->User->ifNativeOptionAvailable($getNativeOptionPaymentCharge['native_option_data']['limit'])) {
15921                    $this->log(__METHOD__ . ' native option limit exceeded.', $logFileName);
15922                    return $this->redirect(myTools::getUrl() . '/mobapp/option/start_disabled'.myTools::getMobappToken($_GET));
15923                }
15924                $this->set('nativeOptionPaymentChargeData', $getNativeOptionPaymentCharge);
15925            }
15926
15927            $initialAmount = $getNativeOptionPaymentCharge['native_option_data']['initial_amount'];
15928            $price_with_coupon = $getNativeOptionPaymentCharge['price_with_coupon'];
15929        }
15930
15931        # NJ-18780 : lite plan native plan
15932        $showLightPlanModal = false;
15933        if (in_array($userData->payment_plan_id, Configure::read('lite_payment_plans'))) {
15934            $showLightPlanModal = true;
15935        }
15936
15937        $this->set('showLightPlanModal', $showLightPlanModal);
15938
15939        $this->set('unli_option_type', $unli_option_type);
15940        $this->set('rt_ck', $this->Cookie->read('rt_ck'));
15941        $this->set('currency', $currency);
15942        $this->set('nativeOptionName', $nativeOptionName);
15943        $this->set('amount', number_format($optionAmount));
15944        $this->set('initialAmount', $initialAmount);
15945        $this->set('currencySymbol', $currencySymbol);
15946        $this->set('prefixSuffixFlg', $prefix_suffix_flg);
15947        $this->set('token', $token);
15948
15949        // -----  NJ-23812 end support for native plan charge --------
15950
15951        $this->set('monthlyPrice', $monthly_price);
15952        $this->set('nativeOption', $amount);
15953        $this->set('symbol', $monthlyPriceSymbol);
15954        $this->set('total', $formatTotal);
15955        $this->set('title_for_layout', __d('register','7日間無料トライアル'));
15956        $this->set('headtext', __d('register','7日間無料トライアル'));
15957        $this->render(myTools::getDeviceUrl() . 'Payment/native_plan');
15958    }
15959
15960    /**
15961     * @api {get} /mobapp/payment/credit_register_questionaire/:token mobapp_credit_register_questionnaire()
15962     * @apiName mobapp_credit_register_questionnaire
15963     * @apiGroup Payment
15964     * @apiDescription This endpoint is used to redirect to the questionnaire page.
15965     * 
15966     * @apiParam {String} token The user's token
15967     * 
15968     * @apiSuccess {View} Redirect to {{ENV}}/mobapp/register/questionnaire/:token
15969     * 
15970     * @apiError {View} Redirect to {{ENV}}/mobapp/retrypage if the token is empty or does not exist.
15971     * 
15972     * @apiSuccessExample Success Response:
15973     * Redirect to {{ENV}}/mobapp/register/questionnaire/:token
15974     * 
15975     * @apiErrorExample Error Response:
15976     * Redirect to {{ENV}}/mobapp/retrypage
15977     * 
15978     * @apiSampleRequest off
15979     */
15980    public function mobapp_credit_register_questionnaire(){
15981        return $this->redirect(myTools::getUrl() . '/mobapp/register/questionnaire'.myTools::getMobappToken($_GET)); 
15982    }
15983
15984    /**
15985     * @api {get} /mobapp/payment/wp_credit/:token mobapp_wp_credit()
15986     * @apiName mobapp_wp_credit
15987     * @apiGroup Payment
15988     * @apiDescription This endpoint is used to display the credit card registration page for WP users.
15989     * 
15990     * @apiParam {String} token The user's token
15991     * 
15992     * @apiSuccess {View} Redirect to {{ENV}}/mobapp/payment/wp_credit_register/:token if
15993     * 
15994     * @apiError {View} Redirect to {{ENV}}/mobapp/retrypage if the token is empty or does not exist.
15995     * 
15996     * @apiSuccessExample Success Response:
15997     * Redirect to {{ENV}}/mobapp/payment/wp_credit_register/:token
15998     * 
15999     * @apiErrorExample Error Response:
16000     * Redirect to {{ENV}}/mobapp/retrypage
16001     * 
16002     * @apiSampleRequest off
16003     */
16004    public function mobapp_wp_credit() {
16005        $this->blockWithdrawnSapuriToS('mobapp');
16006        $this->disablePageForSapuri('mobapp');
16007        $this->layout = "mobapp";
16008        $urlParams = myTools::getMobappToken($_GET);
16009        $logFileName = 'card_registration';
16010        $formType = Configure::read('payment_credit_authentication');
16011        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType));
16012        $userData = $userData['User'];
16013        // redirect to retry page if empty token
16014        if (!isset($this->request->query['token']) || empty($this->request->query['token'])) {
16015            $this->log(
16016                __METHOD__ . ' Query string parameter token does not exist. Parameter(s) --> ' . json_encode($this->request->query) . " | " . json_encode($_SERVER['REQUEST_URI']), 
16017                $logFileName
16018            );
16019            return $this->redirect(myTools::getUrl().'/mobapp/retrypage'.myTools::getMobappToken($_GET));
16020        }
16021
16022        //NJ-13482 Skip Step Re-enrollment
16023        if (isset($userData['id']) && $this->isForTrialReenrollment($userData['id'])) {
16024            return $this->redirect(myTools::getUrl() . '/mobapp/payment/wp_credit_register'.$urlParams);
16025        }
16026        // store to memcached variable
16027        $this->memcache->set(array(
16028            'key' => 'ifUserFromWPPaymentCredit_' . $this->request->query['token'],
16029            'value' => true,
16030            'expire' => 86400
16031        ));
16032
16033        // get api token
16034        $apiToken = $this->request->query['token'];
16035        $isTokenExist = $this->User->find('count', array(
16036            'conditions' => array('api_token' => $apiToken),
16037            'recursive' => -1
16038        ));
16039
16040        // redirect to retry page if api token not exist
16041        if (!$isTokenExist) {
16042            $this->log(__METHOD__ . ' User api token does not exist. api token --> ' . json_encode($apiToken), $logFileName);
16043            return $this->redirect(myTools::getUrl().'/mobapp/retrypage'.myTools::getMobappToken($_GET));
16044        }
16045
16046        // get error from memcache
16047        $error = $this->memcache->get('card_regist_error_'.$apiToken);
16048
16049        // check if there is error
16050        if ($error) {
16051            $this->memcache->delete('card_regist_error_'.$apiToken);
16052            $this->set('error', $error);
16053        }
16054
16055        $this->response->disableCache();
16056        
16057        $this->PhoneVerifyCheckLog->openDBReplica();
16058        $isSMSAuth = $this->PhoneVerifyCheckLog->find('count',array(
16059            'conditions' => array(
16060                'status' => 0,
16061                'user_id' => $userData['id']
16062            ),
16063            'fields' => array(
16064                'phone_number'
16065            ),
16066            'recursive' => -1
16067        ));
16068        $this->PhoneVerifyCheckLog->closeDBReplica();
16069
16070        if ($isSMSAuth || 
16071            $userData['facebook_id'] ||
16072            $userData['google_id'] ||
16073            $userData['line_id'] ||
16074            $userData['apple_id'] ||
16075            $userData['sms_through_flg'] ||
16076            $userData['reason_id']
16077        ) {
16078            $creditRegisterCacheData = array(
16079                'key' => 'success-auth'.$apiToken,
16080                'value' => true,
16081                'expire' => 86400
16082            );
16083            $this->memcache->set($creditRegisterCacheData);
16084        }
16085
16086        $_timeDiff = $this->Timezone->getTimeDiff(
16087            array(
16088                'id' => $this->userData['timezone_id']
16089            )
16090        );
16091        $timeDiff = $_timeDiff * 60;
16092        $date = $this->User->getFirstNextChargeDate();
16093        $time = date('H:59');
16094        $date = date('Y-m-d', strtotime($date)). ' '.$time;
16095
16096        // convert to user time
16097        $userDate = TimezoneTable::computeTimeToUser(array(
16098            'time' => strtotime($date),
16099            'timestamp' => $timeDiff,
16100            'format' => 'Y-m-d'
16101        ));
16102
16103        $this->set('limitFreePeriodGlobal', $userDate);
16104
16105        $this->set('apiToken', $apiToken);
16106        // NC-6879 2020 NEw year campaign
16107        $registrationBonusCoin = Configure::read('credit.bonus_coin_authentication');
16108        $this->set('registrationBonusCoin',  $registrationBonusCoin);
16109        $this->render(myTools::getDeviceUrl() . 'Payment/wp_credit');
16110    }
16111
16112    /**
16113     * @api {post} /mobapp/payment/wp_credit_register/:token mobapp_wp_credit_register()
16114     * @apiName mobapp_wp_credit_register
16115     * @apiGroup Payment
16116     * @apiDescription This endpoint is used to process the credit card registration for WP users.
16117     * 
16118     * @apiParam {String} token The user's token
16119     * 
16120     * @apiBody {Number} cardType The card type (0 = existing card, 1 = new card)
16121     * 
16122     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/wp_credit_register_form/:token if cardType is 1.
16123     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/wp_credit_register_confirm?token=:token if cardType is 0.
16124     * 
16125     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/sms_authentication if the user is not authenticated.
16126     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage amount does not exist / token is invalid.
16127     * 
16128     * @apiExample Example usage:
16129     * {
16130     *         "cardType": 1
16131     * }
16132     * 
16133     * @apiSuccessExample Success Response New Card:
16134     * Redirect to {{ENV}}/mobapp/payment/wp_credit_register_form/:token
16135     * 
16136     * @apiSuccessExample Success Response Existing Card:
16137     * Redirect to {{ENV}}/mobapp/payment/wp_credit_register_confirm?token=:token
16138     * 
16139     * @apiErrorExample Error Response Not Authenticated:
16140     * Redirect to {{ENV}}/mobapp/sms_authentication
16141     * 
16142     * @apiErrorExample Error Response Amount does not exist / token is invalid:
16143     * Redirect to {{ENV}}/mobapp/retrypage 
16144     * 
16145     * @apiSampleRequest off
16146     */
16147    public function mobapp_wp_credit_register() {
16148        $this->blockWithdrawnSapuriToS('mobapp');
16149        $this->disablePageForSapuri('mobapp');
16150        // set variables
16151        $urlParams = myTools::getMobappToken($_GET);
16152        $logFileName = 'card_reregister';
16153        $formType = Configure::read('payment_credit_authentication');
16154        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType));
16155        $user = new UserTable($userData['User']);
16156        $memberType = $user->getUserMembership();
16157        $userData = $userData['User'];
16158        $this->layout = "mobapp";
16159        $this->response->disableCache();
16160        $apiToken = $userData['api_token'];
16161        $currencyCode = $userData['currency_code'];
16162        $memKey = "credit_reregister_{$userData['id']}_{$currencyCode}";
16163        $cardType = $this->memcache->get($memKey);
16164        $cardType = isset($cardType) ? $cardType : 0;
16165
16166        // get monthly price
16167        $amount = $this->PaymentPlanPrice->getMonthlyPrice(array(
16168            'currencyCode' => $currencyCode,
16169            'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
16170            'logFileName' => $logFileName,
16171            'numberFormatFlg' => true
16172        ));
16173        $isCardRegistered = (!empty($userData['card_brand']) && !empty($userData['card_number'])) ? true : false;
16174
16175        if (!isset($amount)) {
16176            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
16177        }
16178
16179        if ($this->request->is('post')) {
16180            $cardType = $this->request->data['cardType'];
16181
16182            // memcache card type value
16183            $this->memcacheCardType(array(
16184                'key' => $memKey,
16185                'value' => $cardType
16186            ));
16187
16188            // redirect to hosted page if using new card ($cardType = 1)
16189            if ($cardType) {
16190                 $this->redirect(myTools::getUrl() . "/mobapp/payment/wp_credit_register_form".$urlParams);
16191            // redirect to confirm page if using existing card ($cardType = 0)
16192            } else {
16193                $this->redirect(myTools::getUrl() . "/mobapp/payment/wp_credit_register_confirm?token=$apiToken");
16194            }
16195        }
16196
16197        // if has complimentary code
16198        if (isset($userData['complimentary_code']) && $userData['complimentary_code']) {
16199            $this->set('cPlan', true);
16200        }
16201
16202        // check if there is error
16203        if ($error = $this->memcache->get('card_register_error_'.$apiToken)) {
16204            $this->memcache->delete('card_register_error_'.$apiToken);
16205            $this->set('error', $error);
16206        }
16207        
16208        // - NJ-23812: display premium data 
16209        $premiumData = $this->PaymentPlanPrice->getPaymentData(array(
16210            'currencyCode' => $currencyCode,
16211            'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
16212            'logFileName' => 'card_reregister'
16213        ));
16214        $currencyData = $this->Currency->getSymbolAndPosition($currencyCode);
16215        
16216        $this->set('monthlyPrice', myTools::formatAmount($premiumData['amount']));
16217        $this->set('monthylyPriceNoTax', myTools::formatAmount($premiumData['amountConstTaxDeducted']));
16218        $this->set('monthlyPriceSymbol',myTools::getCurrencySymbol($currencyCode));
16219
16220
16221        // set view variables
16222        $this->set('cardLogo', myTools::getWorldpayCardLogo($userData['card_brand']));
16223        $this->set('cardBrand', $userData['card_brand']);
16224        $this->set('cardNumber', $userData['card_number']);
16225
16226        $this->set('cardType', $cardType);
16227        $this->set('apiToken', $apiToken);
16228        $this->set('user', $userData);
16229        $this->set('amount', $amount);
16230        
16231        // check if allowed aftee
16232        $this->checkAfteeSupported($userData);
16233
16234        $this->set('title_for_layout', __d('register','7日間無料トライアル'));
16235
16236
16237        // check if allowed aftee
16238        $enableAftee = isset($userData['native_language2']) && $userData['native_language2'] == 'zh-tw' ? 1 : 0;
16239        if (isset($userData['currency_code']) && $userData['currency_code'] != 'TWD') {
16240            $enableAftee = 0;
16241        }
16242
16243        $useAftee = ($enableAftee && $memberType == 'free_user') ? 1 : 0;
16244        $this->set('useAftee', false);
16245
16246        $this->set('enableAftee', false);
16247
16248        // set view variables
16249        $this->set('pmtValue', 'auth');
16250        $this->set('logFileName', $logFileName);
16251        $this->set('worldpayFlg', true);            
16252        $this->set('memKeyError', 'card_register_error_'.$apiToken);
16253        $this->set('referrer', urlencode(myTools::getUrl()."/mobapp/payment/wp_credit_register?token={$apiToken}"));
16254        $this->set('successUrl', urlencode(myTools::getUrl()."/mobapp/payment/notice_to_user?token={$apiToken}&wp=true"));
16255        $this->set('formType', $formType);
16256        $this->set('isCardRegistered',$isCardRegistered);
16257
16258        $this->render(myTools::getDeviceUrl() . 'Payment/wp_credit_register_form');
16259    }
16260
16261    /**
16262     * @api {get} /mobapp/payment/wp_credit_register_form/:token mobapp_wp_credit_register_form()
16263     * @apiName mobapp_wp_credit_register_form
16264     * @apiGroup Payment
16265     * @apiDescription This endpoint is used to display the credit card registration form for WP users.
16266     * 
16267     * @apiParam {String} token The user's token
16268     * 
16269     * @apiSuccess {View} Render Displays the credit card registration form.
16270     * 
16271     * @apiError {View} Redirect to {{ENV}}/mobapp/retrypage if the token is empty or does not exist.
16272     * 
16273     * @apiSuccessExample Success Response:
16274     * Displays the credit card registration form.
16275     * 
16276     * @apiErrorExample Error Response:
16277     * Redirect to {{ENV}}/mobapp/retrypage
16278     * 
16279     * @apiSampleRequest off
16280     */
16281    public function mobapp_wp_credit_register_form() {
16282        $this->blockWithdrawnSapuriToS('mobapp');
16283        $this->disablePageForSapuri('mobapp');
16284        // set variables
16285        $logFileName = 'card_reregister';
16286        $formType = Configure::read('payment_credit_authentication');
16287        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType));
16288        $apiToken = $userData['User']['api_token'];
16289        $this->layout = "mobapp";
16290        $this->response->disableCache();
16291
16292        $isCardRegistered = (!empty($userData['card_brand']) && !empty($userData['card_number'])) ? true : false;
16293
16294        //NJ-23812 :  get monthly price
16295        $amount = $this->PaymentPlanPrice->getMonthlyPrice(array(
16296            'currencyCode' => $currencyCode,
16297            'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
16298            'logFileName' => $logFileName,
16299            'numberFormatFlg' => true
16300        ));
16301
16302
16303        // check if allowed aftee
16304        $this->checkAfteeSupported($userData['User']);
16305
16306        // NJ=23812: set view vars
16307        $this->set('amount', $amount);
16308        $this->set('isCardRegistered', $isCardRegistered);
16309
16310        // set view vars
16311        $this->set('pmtValue', 'auth');
16312        $this->set('apiToken', $apiToken);
16313        $this->set('logFileName', $logFileName);
16314        $this->set('worldpayFlg', true);
16315        $this->set('memKeyError', 'card_register_error_'.$apiToken);
16316        $this->set('referrer', urlencode(myTools::getUrl()."/mobapp/payment/wp_credit_register?token={$apiToken}"));
16317        $this->set('successUrl', urlencode(myTools::getUrl()."/mobapp/payment/notice_to_user?token={$apiToken}&wp=true"));
16318        $this->set('formType', $formType);
16319        $this->set('title_for_layout', '再入会');
16320        $this->render(myTools::getDeviceUrl() . 'Payment/wp_credit_register_form');
16321    }
16322    /**
16323     * @api {post} /mobapp/payment/wp_credit_register_confirm/:token mobapp_wp_credit_register_confirm()
16324     * @apiName mobapp_wp_credit_register_confirm
16325     * @apiGroup Payment
16326     * @apiDescription This endpoint is used to process the credit card registration confirmation for WP users.
16327     * 
16328     * @apiParam {String} token The user's token
16329     * 
16330     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/notice_to_user?token={$apiToken}&wp=true if the payment transaction is successful.
16331     * 
16332     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if the token is empty or does not exist.
16333     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/payment/wp_credit_register?token= with error message if the payment transaction is unsuccessful.
16334     * 
16335     * @apiSuccessExample Success Response:
16336     * Redirect to {{ENV}}/mobapp/payment/notice_to_user?token={$apiToken}&wp=true
16337     * 
16338     * @apiErrorExample Error Response No token:
16339     * Redirect to {{ENV}}/mobapp/retrypage
16340     * 
16341     * @apiErrorExample Error Response Payment Transaction Unsuccessful:
16342     * Redirect to {{ENV}}/mobapp/payment/wp_credit_register?token= with error message
16343     */
16344    public function mobapp_wp_credit_register_confirm() {
16345        // set variables
16346        $logFileName = 'card_reregister';
16347        $formType = Configure::read('payment_credit_authentication');
16348        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType));
16349        $this->layout = "mobapp";
16350        $this->response->disableCache();
16351        $userData = $userData['User'];
16352        $currencyCode = $userData['currency_code'];
16353        $userId = $userData['id'];
16354        $apiToken = $userData['api_token'];
16355        $memKey = "credit_reregister_{$userId}_{$currencyCode}";
16356        $urlParams = myTools::getMobappToken($_GET);
16357
16358        $readSkipConfirmation = true;//NJ-23812:skip the confirmation page
16359
16360        if ($this->request->is('post') || $readSkipConfirmation) {
16361            $paymentMethodType = myTools::getWPPaymentMethodType($userData['card_brand'], 'auth');
16362            $merchantCode = myTools::getWPMerchantCode($paymentMethodType);
16363            $paymentMethod = explode('_', $paymentMethodType);
16364            $paymentMethod = isset($paymentMethod[0]) ? $paymentMethod[0] : null;
16365            $orderCode = myTools::generateOrderCode($userId);
16366            $currencyExponents = Configure::read('worldpay.currency_exponents');
16367            $exponent = $currencyExponents[$currencyCode];
16368            $nominalAmountArr = myTools::getWorldpayNominalAmountList($paymentMethod, $merchantCode);
16369
16370            // get nominal amount with checking currency exponent
16371            $totalAmountArr = myTools::wpGetAmount($exponent, $nominalAmountArr[$currencyCode]);
16372            $ncAmount = $totalAmountArr['ncAmount'];
16373            $wpAmount = $totalAmountArr['wpAmount'];
16374
16375            // get free trial payment data
16376            $freeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
16377                'currencyCode' => $currencyCode,
16378                'paymentPlanId' => Configure::read('payment_plans.free_trial'),
16379                'logFileName' => $logFileName
16380            ));
16381
16382            if (!$freeTrialData) {
16383                return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
16384            }
16385
16386            $userData['payment_plan_id'] = $freeTrialData['paymentPlanId'];
16387            $userData['price_id'] = $freeTrialData['priceId'];
16388
16389            $wpData = array(
16390                'cardToken' => $userData['card_token'],
16391                'merchantCode' => $merchantCode,
16392                'paymentHash' => $orderCode,
16393                'wpPaymentAmount' => $wpAmount
16394            );
16395
16396            // set payment amount
16397            $userData['paymentAmount'] = 0;
16398
16399            // create payment transaction
16400            if (!$pt = $this->createPaymentTransaction($formType, $userData, $wpData)) {
16401                $this->log(__METHOD__ .' Failed to save payment transaction. Params --> ' . json_encode($wpData), $logFileName);
16402                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to save payment transaction. Params --> ' . json_encode($wpData), 'error');
16403                return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
16404            }
16405
16406            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - After save payment transaction. Params --> ' . json_encode($wpData), 'error');
16407
16408            // if aftee payment
16409            if (
16410                $userData['card_company'] == Configure::read('card_company.aftee') ||
16411                ($userData['card_brand'] == "AFTEE" && !empty($userData['aftee_transaction_identifier']))
16412            ) {
16413
16414                // default result
16415                $checkRes = array(
16416                    'OrderCode' => $orderCode,
16417                    'authentication_token' => $userData['card_token'],
16418                    'response' => 'Aftee payment amount is zero',
16419                    'customer' => array(
16420                        'phone_number' =>  $userData['phone_number']
16421                    )
16422                );
16423                $receivableResult = json_encode($checkRes);
16424                $afteeTransactionIdentifier = $userData['aftee_transaction_identifier'];
16425
16426    
16427                if ($userData['paymentAmount'] > 0) {
16428
16429                    if (!class_exists('AfteePaymentService')) {
16430                        App::uses('AfteePaymentService','Lib');
16431                    }
16432                    $afteeService = new AfteePaymentService();
16433                    $afteeChecksumData = array(
16434                        'shopItemId' => "AFTEE" . $formType,
16435                        'itemName' => 'CreditRegisterUsingExistingCard',
16436                        'itemPrice' => $userData['paymentAmount'],
16437                        'itemCount' => 1,
16438                        'customerPhoneNumber' => $userData['phone_number'],
16439                        'customerEmail' => $userData['email'],
16440                        'shopTransactionNo' => $orderCode,
16441                        'userID' =>  $userData['id']
16442                    );
16443                    $checksum = $afteeService->generateChecksum($afteeChecksumData, false);
16444                    $afteeData = array(
16445                        'authentication_token' => $userData['card_token'],
16446                        'related_id' => $userData['aftee_transaction_identifier'],
16447                        'checksum' => $checksum['checksum'],
16448                        'shop_transaction_no' => $orderCode,
16449                        'transaction_options' => array(1)
16450                    );
16451            
16452                    $afteePaymentData = array_merge($afteeData, $checksum['settlementData']);
16453        
16454                    // aftee execute payment
16455                    $receivableResult = $afteeService->directPayment($afteePaymentData);
16456                    $checkRes = json_decode($receivableResult, true);
16457
16458
16459                    if ( isset($checkRes['object']) && $checkRes['object'] == 'transaction') {
16460                        $prPaymentSuccess = true;
16461                    } else if ( !array_key_exists("object", $checkRes) || (isset($checkRes['object']) && $checkRes['object'] == 'error')) {
16462                        $prPaymentSuccess = false;
16463                    }
16464
16465                    $afteeTransactionIdentifier = isset($checkRes['id']) && !empty($checkRes['id']) ? $checkRes['id'] : NULL;
16466                    if (isset($checkRes['related_transaction']) && !empty($checkRes['related_transaction'])) {
16467                        $afteeTransactionIdentifier = $checkRes['related_transaction'];
16468                    }
16469                    $orderCode = isset($checkRes['shop_transaction_no']) && !empty($checkRes['shop_transaction_no']) ? $checkRes['shop_transaction_no'] : NULL;
16470                    $checkRes['OrderCode'] = $orderCode;
16471                }
16472
16473
16474                // process payment data
16475                if ($prPaymentSuccess || $userData['paymentAmount'] == 0) {
16476                    // set user model
16477                    $uModel = $this->User;
16478                    $dataSource = $uModel->getDataSource();
16479                    $dataSource->begin();
16480
16481                    $afteeParams = array(
16482                        'data' => $checkRes,
16483                        'ptData' => $pt,
16484                        'logFileName' => $logFileName,
16485                        'dataSource' => $dataSource,
16486                        'amount' => $userData['paymentAmount'],
16487                        'userData' => $userData,
16488                        'transactionIdentifier' => $afteeTransactionIdentifier,
16489                        'aftee' => 1
16490                    );
16491
16492    
16493                    $this->processAfteePayment($afteeParams);
16494                }
16495
16496                // update payment transaction
16497                $updateData = array(
16498                    'id' => $pt['id'],
16499                    'fields' => array(
16500                        'status' => $prPaymentSuccess,
16501                        'response_text' => array('aftee_directPayment_response' => $receivableResult))
16502                );
16503
16504                // update payment transaction
16505                $this->PaymentTransaction->updateAfteePaymentTransaction($updateData);
16506
16507
16508                // redirect to payment_credit_charge with error display if direct payment response is not authorised
16509                if (!$prPaymentSuccess && $userData['paymentAmount'] > 0) {
16510                    if (!class_exists('myMemcached')) {
16511                        App::uses('myMemcached', 'Lib');
16512                    }
16513                    $memKeyError = 'card_register_error_' . $apiToken;
16514                    $memerror = __('トランザクションを完了できません。 もう一度お試しください。');
16515                    $memcached = new myMemcached();
16516                    $memcached->set(array(
16517                        'key' => $memKeyError,
16518                        'value' => $memerror,
16519                        'expire' => 3600 // 1 hour
16520                    ));
16521                    return $this->redirect(myTools::getUrl() . '/mobapp/payment/wp_credit_register?token='.$apiToken);
16522                }
16523                // default worldpay
16524            } else {
16525
16526                $wpData = array(
16527                    'merchantCode' => $merchantCode,
16528                    'orderCode' => $orderCode,
16529                    'description' => 'Credit Register Using Existing Card',
16530                    'currencyCode' => $currencyCode,
16531                    'exponent' => $exponent,
16532                    'amount' => $wpAmount,
16533                    'cardToken' => $userData['card_token'],
16534                    'email' => $userData['email'],
16535                    'authenticatedShopperId' => $userId,
16536                    'xmlName' => 'direct_payment_with_token',
16537                    'shopperIpAddress' => $_SERVER["REMOTE_ADDR"],
16538                    'wpTransactionIdentifier' => $userData['wp_transaction_identifier'],
16539                    'paymentMethod' => $paymentMethod
16540                );
16541
16542                $result = wpPaymentService::directPayment($wpData);
16543
16544                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - directPayment result --> ' . json_encode($result), 'error');
16545
16546                $updateData = array(
16547                    'id' => $pt['id'],
16548                    'fields' => array('response_text' => array('directPayment_response' => $result)),
16549                    'logFileName' => $logFileName
16550                );
16551
16552                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - before updatePaymentTransaction result --> ' . json_encode($updateData), 'error');
16553
16554                // redirect to retry page if failed to update payment transaction
16555                if (!$this->updatePaymentTransaction($updateData)) {
16556                    return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
16557                }
16558
16559                // redirect to wp_credit_register with error display if direct payment response is not authorised
16560                if (!myTools::checkIfWPPaymentResponseIsAuthorised($result)) {
16561                    $params = array(
16562                        'apiToken' => $apiToken,
16563                        'wpResponse' => $result,
16564                        'memKey' => 'card_register_error_' . $apiToken
16565                    );
16566                    myTools::parseAndSetWPErrorResponse($params);
16567                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - WP Payment not authorised --> ' . json_encode($params), 'error');
16568                    return $this->redirect(myTools::getUrl() . '/mobapp/payment/wp_credit_register?token='.$apiToken);
16569                }
16570            }
16571
16572            // delete memcache
16573            if ($this->memcache->get($memKey)) {
16574                $this->memcache->delete($memKey);
16575            }
16576            // send registration completion email
16577            App::uses('myMailer','Lib');
16578            $mail_id = Configure::read('site_in_mail.student_registration_complete');
16579            if ($userData &&  !in_array($userData['currency_code'], Configure::read('global_free_trail_currencies') ) ) {
16580                $mail_id = Configure::read('site_in_mail.registration_no_trial_currencies');
16581            }
16582
16583            myMailer::sendTemplateMail($mail_id, $userData['email'], $userData, array(), 'User');
16584
16585            $stepKey = Configure::read('registration_steps.credit_card_registration_success');
16586            $this->saveStep($userId, $stepKey);
16587
16588            $this->Session->write('reenroll_native_option', true);
16589            return $this->redirect(myTools::getUrl() . "/mobapp/payment/notice_to_user?token={$apiToken}&wp=true");
16590        }
16591
16592        // set view variables
16593        $this->set('title_for_layout', __d('register','無料トライアル'));
16594        $this->set('cardLogo', myTools::getWorldpayCardLogo($userData['card_brand']));
16595        $this->set('apiToken', $apiToken);
16596        $this->set('cardBrand', $userData['card_brand']);
16597        $this->set('cardNumber', $userData['card_number']);
16598        $this->render(myTools::getDeviceUrl() . 'Payment/wp_credit_register_confirm');
16599    }
16600
16601    /**
16602     * @api {get} /mobapp/payment/credit_charge/:token mobapp_credit_charge()
16603     * @apiName mobapp_credit_charge
16604     * @apiGroup Payment
16605     * @apiDescription this endpoint is used to process the credit card charge for mobapp users.
16606     * 
16607     * @apiParam {String} token The user's token
16608     * 
16609     * @apiSuccess {View} Render Displays the credit card charge form.
16610     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/close if user has already paid.
16611     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/wp_credit_charge if the user's currency is not JPY.
16612     * @apiSuccess {View} Redirect Redirects to {{ENV}}//mobapp/payment/credit_charge_form if the user is temporary and does not have a card number.
16613     * 
16614     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if the token is empty or does not exist.
16615     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage If the user is a paid member or a Chocotto camp paid member and not on a complimentary plan.
16616     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage If the premium payment plan is not supported.
16617     * @apiError {View} Redirect Redirects to {{{ENV}}}/mobapp/retrypage If the corporate payment plan data is not supported
16618     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if the payment transaction creation fails.
16619     * 
16620     * @apiSuccessExample Success Response:
16621     * Displays the credit card charge form.
16622     * 
16623     * @apiSuccessExample Success Response User Already Paid:
16624     * Redirect to {{ENV}}/mobapp/close
16625     * 
16626     * @apiSuccessExample Success Response Currency Not JPY:
16627     * Redirect to {{ENV}}/mobapp/payment/wp_credit_charge
16628     * 
16629     * @apiSuccessExample Success Response Temporary User:
16630     * Redirect to {{ENV}}//mobapp/payment/credit_charge_form
16631     * 
16632     * @apiErrorExample Error Response No Token:
16633     * Redirect to {{ENV}}/mobapp/retrypage
16634     * 
16635     * @apiErrorExample Error Response User is Paid Member or Chocotto Camp Paid Member and Not on Complimentary Plan:
16636     * Redirect to {{ENV}}/mobapp/retrypage
16637     * 
16638     * @apiErrorExample Error Response Premium Payment Plan Not Supported:
16639     * Redirect to {{ENV}}/mobapp/retrypage
16640     * 
16641     * @apiErrorExample Error Response Corporate Payment Plan Data Not Supported:
16642     * Redirect to {{ENV}}/mobapp/retrypage
16643     * 
16644     * @apiErrorExample Error Response Payment Transaction Creation Failed:
16645     * Redirect to {{ENV}}/mobapp/retrypage
16646     * 
16647     * @apiSampleRequest off
16648     */
16649    public function mobapp_credit_charge() {
16650        if ($this->Session->read('mobapp_show_welcome_back_modal')){
16651            $this->Session->delete('mobapp_show_welcome_back_modal');
16652        }
16653
16654        $this->response->disableCache();
16655        $this->blockWithdrawnSapuriToS('mobapp');
16656        $this->disablePageForSapuri('mobapp');
16657        // set variables
16658        $this->layout = 'mobapp';
16659        $logFileName = 'card_charge';
16660        $urlParams = myTools::getMobappToken($_GET);
16661        $formType = Configure::read('payment_credit_force_charge');
16662        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType)); // get user data and validate
16663
16664        // NJ-30828: set view to display user's paypal email
16665        $this->setPaypalUser($userData);
16666
16667        // - check user if already paid
16668        $userDetails = new UserTable($userData['User']);
16669
16670        $creditChargePaymentSucessFlg = $this->memcache->get('creditChargePaymentSucess' . $userDetails->id);
16671        if($creditChargePaymentSucessFlg) {
16672            return $this->redirect(array('controller' => 'Mobapp', 'action' => 'close', '?' => array('token'=> $userDetails->api_token, 're_enrolled' => 1)));
16673        }
16674
16675        $memberType = $userDetails->getUserMembership();
16676        if(
16677            in_array(
16678                $memberType,
16679                [
16680                    Configure::read('user.member_type_paid'),
16681                    Configure::read('user.member_chocotto_camp_paid')
16682                ]
16683            ) &&
16684            $userDetails->payment_plan_id != Configure::read('payment_plans.complimentary_plan')
16685        ) {
16686            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
16687        }
16688
16689        $userData = $userData['User'];
16690        $_user = $userData;
16691        $enableChocottoPlan = true;
16692        $this->restrictForTrialNotConducted($userData, $urlParams);
16693        // redirect to worldpay if not zuespay user (currency != JPY)
16694        if ($userData['currency_code'] != Configure::read('currency_jpy')) {
16695            return $this->redirect(myTools::getUrl() . '/mobapp/payment/wp_credit_charge'.$urlParams);
16696        }
16697
16698        $isCompUser = (isset($userData['complimentary_code']) && $userData['complimentary_code']) ? true : false;
16699        $this->set('isCompUser',$isCompUser);
16700
16701        $this->setPerMonthSymbol($_user['native_language2'], true);
16702
16703        $trialNumber = 0;
16704        if(
16705            $isCompUser &&
16706            $memberType == Configure::read('user.member_type_paid') && 
16707            $userDetails->payment_plan_id == Configure::read('payment_plans.complimentary_plan')
16708        ) {
16709            $checkExpiry = $this->ComplimentaryCode->getCCLessonRemAndExpiryDate($userDetails);
16710            if (
16711                !empty($checkExpiry) &&
16712                $checkExpiry['templateType'] == 0 &&
16713                $checkExpiry['expiryDate'] >= date('Y-m-d H:i') &&
16714                $checkExpiry['lessonRem'] > 0
16715            ) {
16716                $trialNumber = 7;
16717            }
16718        }
16719
16720        $apiToken = $this->request->query['token'];
16721        $appVersion = $this->request->query['appVersion'];
16722        $deviceType = $this->request->query['deviceType'];
16723        $couponData = $this->Session->read('apply_coupon_usage_data');
16724        $isFreeFlg  = false;
16725        $freeNumber = 0;
16726        $monthlyFee = 0;
16727        $corporateIndiUser = false;
16728
16729        $this->set('appVersion', $appVersion);
16730        $this->set('deviceType', $deviceType);
16731
16732        // get premium plan data
16733        $ppData = $this->PaymentPlanPrice->getPaymentData(array(
16734            'currencyCode' => $userData['currency_code'],
16735            'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
16736            'logFileName' => $logFileName
16737        ));
16738
16739        // redirect to retry page if premium payment plan is not supported
16740        if (!$ppData) {
16741            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
16742        }
16743
16744        $corporateUser = isset($userData['corporate_id']) ? true : false;
16745
16746        $annualDiscountOptionData = $this->DiscountOptionsPrice->getPaymentData(['currencyCode' => $userData['currency_code'], 'discountOptionId' => Configure::read('discount_option.annual.plan_id')]);
16747        $annualDiscountOptionAmount = 0;
16748
16749        // - check if there is annual discount option data
16750        if ($annualDiscountOptionData) {
16751            $annualDiscountOptionAmount = myTools::formatAmount($annualDiscountOptionData['amount']);
16752        } 
16753
16754        $this->set('enableAnnualDiscountOption', $annualDiscountOptionData ? true : false);
16755        $this->set('annualDiscountOptionAmount', $annualDiscountOptionAmount);
16756
16757        // get corporate payment method
16758        $this->Corporate->openDBReplica();
16759        $corporateData = $this->Corporate->find('first', array(
16760            'fields' => array('payment_method'),
16761            'conditions' => array('id' => $userData['corporate_id']),
16762            'recursive' => -1
16763        ));
16764        $this->Corporate->closeDBReplica();
16765
16766        $corporateData = $corporateData ? $corporateData['Corporate'] : null;
16767
16768        // if corporate user
16769        if ($corporateUser && $corporateData && $corporateData['payment_method'] == 1) {
16770            // get corporate payment plan data
16771            $cpData = $this->getCorporatePaymentPlan($userData);
16772
16773            // redirect to retry page if not supported
16774            if (!$cpData) {
16775                return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
16776            }
16777
16778            $cfAmount = $cpData['fAmount'];
16779            $corporateIndiUser = $cpData['corporateIndiUser'];
16780        }
16781
16782        // delete old card charge token
16783        $this->memcache->delete('card-charge-'.$apiToken);
16784
16785        $cardToken = md5 (uniqid(rand(), true));
16786
16787        // save new card charge token to memcache
16788        $this->memcache->set(array(
16789            'key' => 'card-charge-'.$apiToken,
16790            'value' => $cardToken,
16791            'expire' => 3600
16792        ));
16793
16794        $corporateMemKey = 'mobappCreditChargeCorporateData_' . $userData['id'];
16795
16796        // delete if exist
16797        if ($this->memcache->get($corporateMemKey)) {
16798            $this->memcache->delete($corporateMemKey);
16799        }
16800
16801
16802        $cAmount = $lightTotalLessFee =  0;
16803        $corpType = myTools::getCoporateTypeUsingPaymentPlanId($userData['payment_plan_id']);
16804        if ($corporateIndiUser) {
16805            $corporateTaxRate = Configure::read('tax.increase');
16806            
16807            // light
16808            if ($corpType == Configure::read('corporate_type.light')) {
16809                $indiLightPlanUser = true;
16810                $getCorporateData = $this->Corporate->getCorporateLightUserMonthly(array('user_id' => $userData['id']));
16811                $paymentAmount = isset($getCorporateData['total']) ? $getCorporateData['total'] : 0;
16812                $basicFee = isset($getCorporateData['basic_fee']) ? $getCorporateData['basic_fee'] : 0;
16813                $lessonFee = isset($getCorporateData['lesson_fee']) ? $getCorporateData['lesson_fee'] : 0;
16814                $basicFeeWoTax = isset($getCorporateData['basic_fee_discounted']) ? $getCorporateData['basic_fee_discounted'] : 0;
16815                $freeNumber = isset($getCorporateData['fee_charge_count']) ? $getCorporateData['fee_charge_count'] : 0;
16816                $isFreeFlg = isset($getCorporateData['free_charge_flg']) ? $getCorporateData['free_charge_flg'] : false;
16817                $monthlyFee = isset($getCorporateData['monthly_fee_wo_tax']) ? $getCorporateData['monthly_fee_wo_tax'] : 0;
16818                $cfAmount = myTools::formatAmount($basicFeeWoTax);
16819                $lessonLimit = $this->Corporate->getLessonLimit($userData['corporate_id']);
16820                $cAmount = $basicFeeWoTax;
16821                $lightDiscount = isset($getCorporateData['discount']) ? $getCorporateData['discount'] : 0;
16822                $lightTotalLessFee = $monthlyFee + $lightDiscount;
16823
16824                $corporateMemData = array(
16825                    'lessonFee' => $lessonFee,
16826                    'basicFee' => $basicFee,
16827                    'freeFlg' => $isFreeFlg,
16828                    'freeNumber' => $freeNumber,
16829                    'monthlyFee' => $monthlyFee,
16830                    'fAmount' => $cfAmount,
16831                    'paymentAmount' => $paymentAmount * $corporateTaxRate,
16832                    'lessonLimit' => $lessonLimit,
16833                    'paymentPlanId' => $cpData['paymentPlanId'],
16834                    'priceId' => $cpData['priceId']
16835                );
16836            // standard or premium
16837            } elseif (in_array($corpType, array(Configure::read('corporate_type.premium'), Configure::read('corporate_type.standard')))) {
16838                $cdrParam = array('corporateId' => $userData['corporate_id'], 'corporateType' => $corpType);
16839                $discount = (int)$this->CorporateDiscountRate->getDiscount($cdrParam);
16840                $cAmount = $cpData['amount'] - $discount;
16841                $cfAmount = myTools::formatAmount($cAmount);
16842                $corporateMemData = array(
16843                    'cprAmount' => $cpData['amount'],
16844                    'cprDiscount' => $discount,
16845                    'paymentAmount' => $cAmount * $corporateTaxRate,
16846                    'fAmount' => $cfAmount,
16847                    'paymentPlanId' => $cpData['paymentPlanId'],
16848                    'priceId' => $cpData['priceId']
16849                );
16850            }
16851
16852            if (isset($corporateMemData)) {
16853                $this->memcache->set(array(
16854                    'key' => $corporateMemKey,
16855                    'value' => $corporateMemData,
16856                    'expire' => 3600 // 1 hr
16857                ));
16858            }
16859
16860            // if user is temporary redirect to form input after setting corporate memcached data needed later
16861            if ($userData['status'] == 0 && empty($user['card_number']) && empty($user['card_brand'])) {
16862
16863                $this->redirect(myTools::getUrl() . '/mobapp/register/corporate_creditform'.$urlParams); // New Corporate Users without Force to register a card
16864            }
16865        }
16866
16867        $userData = $this->changePaymentPlanIfTelecomUser($userData);
16868
16869        // get and delete errors
16870        if ($error = $this->memcache->get('card-error-'.$apiToken)) {
16871            $this->memcache->delete('card-error-'.$apiToken);
16872        }
16873
16874        // if complimentary plan
16875        if (isset($userData['com_plan_user']) && $userData['com_plan_user']) {
16876            $_cPlan = false;
16877
16878            // set com_plan_user to true if payment plan id is not null and is complimentary plan
16879            if (isset($userData['payment_plan_id']) && $userData['payment_plan_id'] == Configure::read('payment_plans.complimentary_plan')){
16880                $_cPlan = true;
16881            // set com_plan_user to true if payment plan id is null and is complimentary plan
16882            } elseif (!isset($userData['payment_plan_id']) && $this->Payment->ifComPlanUser($userData['id'])) {
16883                $_cPlan  = true;
16884            }
16885    
16886            $this->set('cPlan', $_cPlan);
16887        } else {
16888            // NC-3914
16889            $this->getAndSetCardInfo($userData);
16890        }
16891
16892        $isFamilyPlanBefore = PaymentTable::checkIfFamilyPlan(
16893            $userData['id'],
16894            $userData['hash16'],
16895            array(
16896                Configure::read('payment_credit_family_free'),
16897                Configure::read('payment_credit_family_monthly_payment')
16898            )
16899        );
16900
16901        $this->set('isFamilyPlanBefore', $isFamilyPlanBefore);
16902        $this->set('data', $this->memcache->get('mobappUserCreditChargeInfo_'.$apiToken));
16903
16904        $currencyCode = $userData['currency_code'];
16905        $pDataDisplay = $this->PaymentPlanPrice->getPaymentData(array(
16906            'currencyCode' => $currencyCode,
16907            'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
16908            'logFileName' => 'card_reregister'
16909        ));
16910
16911        $annualDiscountOption = $this->DiscountOptionsPrice->getPaymentData(['currencyCode' => $currencyCode, 'discountOptionId' => Configure::read('discount_option.annual.plan_id')]);
16912        $annualDiscountOptionAmount = $annualDiscountOption ? $annualDiscountOption['amount'] : 0;
16913
16914        // - check if there is annual discount option data
16915        if ($annualDiscountOption) {
16916            unset($annualDiscountOption['contract_start']);
16917            $annualDiscountOption += [
16918                'dosh_event' => Configure::read('discount_option.dosh_event.annual_discount'),
16919                'dosh_status' => Configure::read('discount_option.dosh_status.monthly_discount')
16920            ];
16921
16922            $annualDiscountOptionAmount = $annualDiscountOption['amount'];
16923        }
16924
16925        $monthlyPriceWithAnnualDiscount = $pDataDisplay['amount'] - $annualDiscountOptionAmount;
16926        $monthlyPriceWithAnnualDiscountNoTax = $monthlyPriceWithAnnualDiscount / Configure::read('added_tax_percentage');
16927        $monthlyPriceWithAnnualDiscountNoTax = round($monthlyPriceWithAnnualDiscountNoTax);
16928
16929        $this->set('enableAnnualDiscountOption', $annualDiscountOption ? true : false);
16930        $this->set('annualDiscountOptionAmount', myTools::formatAmount($annualDiscountOptionAmount));
16931        $this->set('monthlyPriceWithAnnualDiscount', myTools::formatAmount($monthlyPriceWithAnnualDiscount));
16932        $this->set('monthlyPriceWithAnnualDiscountNoTax', myTools::formatAmount($monthlyPriceWithAnnualDiscountNoTax));
16933
16934        // if corporate individual user
16935        if (isset($cpData)) {
16936            $this->set('cAmount',$cAmount);
16937            $this->set('cpFormatAmount', $cfAmount);
16938        }
16939
16940        $mobappCorpIndividualData = array(
16941            'apiToken' => $apiToken,
16942        );
16943        
16944        // data needed for corporate individual
16945        if ($corporateIndiUser) {
16946            $this->corpIndividualData($userData,$mobappCorpIndividualData);
16947        }
16948
16949        $currencyData = $this->Currency->getSymbolAndPosition($userData['currency_code']);
16950        $this->set('monthlyPrice', myTools::formatAmount($ppData['amount']));
16951        $this->set('monthylyPriceNoTax', myTools::formatAmount($ppData['amountConstTaxDeducted']));
16952        $this->set('monthlyPriceSymbol',myTools::getCurrencySymbol($userData['currency_code']));
16953        $this->set('lightTotalLessFee',$lightTotalLessFee);
16954
16955
16956        $this->setSupportPayPal($userData);
16957        $this->set('userData', $userData);
16958        $this->set('amount', $ppData['amount']);
16959        $this->set('ppFormatAmount', $ppData['fAmount']);
16960        $this->set('corporateIndiUser', $corporateIndiUser);
16961        $this->set('error', $error);
16962        $this->set('apiToken', $apiToken);
16963        $this->set('cardToken', $cardToken);
16964        $this->set('zeusTransactionFlag', true);
16965        $this->set('lessonLimit', isset($lessonLimit) ? $lessonLimit : 0);
16966        $this->set('indiLightPlanUser', isset($indiLightPlanUser) ? $indiLightPlanUser : false);
16967        $this->set('corporateType', $corpType);
16968        $this->set('isFreeFlg', $isFreeFlg);
16969        $this->set('freeNumber', $freeNumber);
16970        $this->set('monthlyFee', $monthlyFee);
16971        $this->set('corporateUser', $corporateUser);
16972        $this->set('paymentHash', '');
16973
16974        if ($trialNumber) {
16975            $this->set('title_for_layout', sprintf(__d('payment', '%s日間無料トライアル'), $trialNumber));
16976        } else {
16977            $this->set('title_for_layout', '再入会');
16978        }
16979
16980        $this->set('zeusCC', Configure::read('card_company.zeus'));
16981        $this->set('paypalCC', Configure::read('card_company.paypal'));
16982        $this->set('paypalUserData', $userData);
16983        $this->set('userApiToken', $apiToken);
16984        
16985        // NJ-23812 : redirect to credit charge form 
16986        $this->set('failURLReferer', myTools::getUrl() . "/mobapp/payment/credit_charge" . myTools::getMobappToken(array_merge(array('token' => $apiToken ), $_GET)) );
16987        $this->set('monthlyPriceSymbol', myTools::getCurrencySymbol($userData['currency_code']));
16988
16989        // NJ-32737
16990        $this->setCouponUseData($userData['id'], $userData['currency_code']);
16991
16992
16993            $this->set('paypalUserData', $userData);
16994            $this->set('userApiToken', $apiToken);
16995            // prepare the data if incase users using paypal payment method
16996            $data['paymentPlanData'] = $ppData;
16997            $data['receivablePayment'] = $this->PaymentReceivable->computeReceivableReservationPayment($userData['id']);
16998            $data['appreciationReceivable'] = $this->PaymentReceivable->computeReceivableReservationPayment($userData['id'], false, Configure::read('appreciation_data.payment_element_type'));
16999            $data['liveLessonReceivable'] = $this->PaymentReceivable->computeReceivableReservationPayment($userData['id'], false, Configure::read('payment_element_type.live'));
17000            $data['formType'] = $formType;
17001            $this->memcache->set(array(
17002                'key' => 'mobappPaypalPaymentCreditChargeData_' . $apiToken,
17003                'value' => $data,
17004                'expire' => 3600 // 1 hour
17005            ));
17006
17007            /**
17008             * Existing code for NJ-19183 displays the credit form in this page instead of /mobapp/payment/credit_charge_form
17009             * This is paymentHash support for NJ-2552 3D secure challenge
17010             * Goal: Prepopulate paymenthash value
17011             */
17012            $userDataArr = $userData;
17013            $paymentData = $ppData;
17014            $paymentPlanType = $data['ZPaymentFullLogs']['payment_plan_type'];
17015            // if retain indi plan
17016            if (!$corporateIndiUser) {                    
17017                $userDataArr['paymentAmount'] = $paymentData['amount'];
17018                $userDataArr['price_id'] = $paymentData['priceId'];
17019                $userDataArr['payment_plan_id'] = $paymentData['paymentPlanId'];
17020
17021                $data['ZPaymentFullLogs']['formType'] = $formType;
17022
17023                // add reserve payment receivable
17024                $userDataArr['paymentAmount'] +=  $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id']);
17025
17026                // add appreciation payment receivable
17027                $userDataArr['paymentAmount'] +=  $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('appreciation_data.payment_element_type'));
17028
17029                // add live lesson payment receivable
17030                $userDataArr['paymentAmount'] +=  $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('payment_element_type.live'));
17031                
17032                // add annual discount option
17033                if (
17034                    $annualDiscountOption &&
17035                    $paymentPlanType == Configure::read('register_plan_types.premium_with_annual_discount_option')
17036                ) {
17037                    $data['discountOption'] = $user['discountOption'] = $annualDiscountOptionData;
17038                }
17039
17040
17041
17042                $membershipStatusIndex = UserTable::getStudentMembershipStatus($userDataArr['id']);
17043                if (in_array($membershipStatusIndex, Configure::read('allow_coupon.settlement')) &&
17044                    isset($data['z_payment_form_type']) &&
17045                    in_array($data['z_payment_form_type'], Configure::read('allow_coupon.settlement_form_type'))
17046                ) {
17047                    if (isset($couponData['useCouponAmount']) && $couponData['useCouponAmount'] > 0) {
17048                        if ($data['ZPaymentFullLogs']['money'] >= $couponData['useCouponAmount']) {
17049                            $data['ZPaymentFullLogs']['money'] -= $couponData['useCouponAmount'];
17050                        } else {
17051                            $data['ZPaymentFullLogs']['money'] = 0;
17052                        }
17053
17054                        $userDataArr['couponUseSettlement'] = $couponData;
17055
17056                        // payment amount - coupon amount
17057                        $userDataArr['paymentAmount'] = $data['ZPaymentFullLogs']['money'];
17058
17059                    }
17060                }
17061
17062                if (!$pt = $this->createPaymentTransaction($formType, $userDataArr)) {
17063                    return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
17064                }
17065                $this->set('paymentHash', $pt['payment_hash']);
17066            }
17067            // redirect to retry page if failed to create payment transaction
17068            
17069            /**
17070             * NJ-19183 | NJ-25522 support end
17071             */
17072            $comp_plan_page = 'credit_charge';
17073            if ($isCompUser) {
17074                $comp_plan_page = "not_allowed_lite_plan_change";
17075                $ccData = $this->ComplimentaryCode->find('first', 
17076                    array(
17077                        'fields' => array('available_days','template_type '),
17078                        'conditions' => array(
17079                            'code' => $_user['complimentary_code'],
17080                            'template_type !=' => 0
17081                        )
17082                ));
17083
17084                if ($ccData) {
17085                    $comp_plan_page = 'credit_charge';
17086                }
17087            }
17088
17089            // NJ-18780 : set view support for lite plan
17090            $this->setLitePaymentInfoView($_user,false,false,$comp_plan_page);
17091
17092        #chocotto plan data
17093        $chocottoPlanData = $this->PaymentPlanPrice->getPaymentData(array(
17094            'currencyCode' => $_user['currency_code'],
17095            'paymentPlanId' => Configure::read('payment_plans.chocotto_plan'),
17096            'logFileName' => $logFileName ?? 'card_reregister'
17097        ));
17098
17099        // - set chocotto plan price
17100        $this->set('chocottoMonthlyPrice',$chocottoPlanData['fAmount']);
17101        $this->set('chocottoMonthlyPriceNoTax', myTools::formatAmount($chocottoPlanData['amountConstTaxDeducted']));            
17102
17103            $this->render(myTools::getDeviceUrl().'Payment/credit_charge_form');
17104    }
17105
17106    /**
17107     * @api {post} /mobapp/payment/credit_charge_form/:token/:cardToken mobapp_credit_charge_form()
17108     * @apiName mobapp_credit_charge_form
17109     * @apiGroup Payment
17110     * @apiDescription This endpoint is used to display and process the credit card charge form for mobapp users.
17111     * 
17112     * @apiParam {String} token The user's token
17113     * @apiParam {String} cardToken The card token
17114     * 
17115     * @apiBody {String} token The user's token.
17116     * @apiBody {String} cardToken The card token.
17117     * @apiBody {Object} ZPaymentFullLogs The payment logs object.
17118     * @apiBody {String} ZPaymentFullLogs.payment_plan_type The payment plan type.
17119     * @apiBody {String} ZPaymentFullLogs.paymentHash The payment hash.
17120     * @apiBody {Number} ZPaymentFullLogs.money The payment amount.
17121     * @apiBody {String} ZPaymentFullLogs.formType The form type.
17122     * @apiBody {String} ZPaymentFullLogs.telno The default telephone number.
17123     * @apiBody {String} ZPaymentFullLogs.clientip The client IP address.
17124     * @apiBody {Number} ZPaymentFullLogs.indiCorpType The individual corporate type.
17125     * @apiBody {String} [ZPaymentFullLogs.corporatePlan] The corporate plan type 
17126     * @apiBody {Object} [discountOption] The discount option data .
17127     * @apiBody {String} [discountOption.dosh_event] The discount event.
17128     * @apiBody {String} [discountOption.dosh_status] The discount status.
17129     * @apiBody {Number} [discountOption.amount] The discount amount.
17130     * @apiBody {Object} [paymentPlanData] The payment plan data . This is required if user is paypal user.
17131     * @apiBody {Number} [paymentPlanData.amount] The payment amount.
17132     * @apiBody {Number} [paymentPlanData.fAmount] The formatted payment amount.
17133     * @apiBody {Number} [paymentPlanData.priceId ]The price ID.
17134     * @apiBody {Number} [paymentPlanData.paymentPlanId] The payment plan ID.
17135     * @apiBody {Number} receivablePayment The receivable payment amount 
17136     * @apiBody {Number} appreciationReceivable The appreciation receivable amount 
17137     * @apiBody {Number} liveLessonReceivable The live lesson receivable amount 
17138     * @apiBody {String} userApiToken The user's API token (optional).
17139     * @apiBody {Object} [userData] The user data (optional).
17140     * @apiBody {Number} [userData.id] The user ID.
17141     * @apiBody {String} [userData.currency_code] The user's currency code.
17142     * @apiBody {Number} [userData.payment_plan_id] The user's payment plan ID.
17143     * @apiBody {Number} [userData.price_id] The user's price ID.
17144     * @apiBody {Number} [userData.paymentAmount] The user's payment amount.
17145     * @apiBody {Number} [userData.corporate_id] The user's corporate ID.
17146     * @apiBody {Number} [userData.lesson_fee] The user's lesson fee.
17147     * @apiBody {Number} [userData.basic_fee] The user's basic fee.
17148     * @apiBody {Number} [userData.cprAmount] The corporate receivable amount.
17149     * @apiBody {Number} [userData.cprDiscount] The corporate receivable discount.
17150     * @apiBody {String} [userData.corporateSettlementType] The corporate settlement type.
17151     * @apiBody {String} [userData.statusAfter] The user's status after payment.
17152     * @apiBody {String} [userData.statusBefore] The user's status before payment.
17153     * @apiBody {Object} [couponUseSettlement] The coupon use settlement data .
17154     * @apiBody {Number} [couponUseSettlement.useCouponAmount] The coupon use amount.
17155     * 
17156     * @apiSuccess {View} Render Displays the credit card charge form.
17157     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/paypal_payment_credit_charge_confirm?token={{token}} if the user is using PayPal.
17158     * @apiSuccess {View} Redirect Redirects to {{ENV}}/payment/mobapp_credit_charge_confirm if the form submission is successful.
17159     * 
17160     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if the token is empty or does not exist.
17161     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if the premium payment plan data is not supported.
17162     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if the corporate payment plan data is not supported.
17163     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if the payment transaction creation fails.
17164     * 
17165     * @apiExample Example usage:
17166     * {
17167     *         "token": "user_token",
17168     *       "cardToken": "card_token",
17169     *       "ZPaymentFullLogs": {
17170     *             "payment_plan_type": "premium",
17171     *             "paymentHash": "hash_value",
17172     *             "money": 1000,
17173     *             "formType": "force_charge",
17174     *             "telno": "1234567890",
17175     *             "clientip": "192.168.1.1",
17176     *             "indiCorpType": 1,
17177     *       },
17178     *      "receivablePayment": 100,
17179     *       "appreciationReceivable": 50,
17180     *       "liveLessonReceivable": 30,
17181     *       "userApiToken": "user_api_token"
17182     * }
17183     * 
17184     * @apiSuccessExample Success Response:
17185     * Display the credit card charge form.
17186     * 
17187     * @apiSuccessExample Success Response User is using PayPal:
17188     * Redirects to {{ENV}}/mobapp/payment/paypal_payment_credit_charge_confirm?token={{token}}
17189     * 
17190     * @apiSuccessExample Success Response Form submission is successful:
17191     * Redirects to {{ENV}}/payment/mobapp_credit_charge_confirm
17192     * 
17193     * @apiErrorExample Error Response Token is empty or does not exist:
17194     * Redirects to {{ENV}}/mobapp/retrypage
17195     * 
17196     * @apiErrorExample Error Response Premium payment plan data is not supported:
17197     * Redirects to {{ENV}}/mobapp/retrypage
17198     * 
17199     * @apiErrorExample Error Response Corporate payment plan data is not supported:
17200     * Redirects to {{ENV}}/mobapp/retrypage
17201     * 
17202     * @apiErrorExample Error Response Payment transaction creation fails:
17203     * Redirects to {{ENV}}/mobapp/retrypage
17204     * 
17205     * @apiSampleRequest off
17206     */
17207    public function mobapp_credit_charge_form(){
17208        $this->blockWithdrawnSapuriToS('mobapp');
17209        $this->disablePageForSapuri('mobapp');
17210        $this->layout = 'mobapp';
17211        $this->response->disableCache();
17212        $urlParams = myTools::getMobappToken($_GET);
17213        $logFileName = 'card_charge';
17214        $formType = Configure::read('payment_credit_force_charge');
17215        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType)); // get user data and validate
17216        $requestQuery = $this->request->query;
17217        $apiToken = $requestQuery['token'];
17218        $paymentPlanId = Configure::read('payment_plans.premium_plan');
17219        $cardToken = isset($requestQuery['cardToken']) ? $requestQuery['cardToken'] : '';
17220        $memKey = 'mobappUserCreditChargeInfo_'.$apiToken;
17221        $userDataArr = $userData['User'];
17222        $corporateChargeMemData = array();
17223        $requestData = $this->request->data;
17224
17225        // get premium payment plan data
17226        $paymentData = $this->PaymentPlanPrice->getPaymentData(array(
17227            'currencyCode' => $userDataArr['currency_code'],
17228            'paymentPlanId' => $paymentPlanId,
17229            'logFileName' => $logFileName
17230        ));
17231
17232        if (!$paymentData) {
17233            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
17234        }
17235
17236        $amount = $paymentData['amount'];
17237        $fAmount = $paymentData['fAmount'];
17238        $retainIndiPlan = null;
17239        $corporateIndiUser = false;
17240
17241            $corporateUser = isset($userDataArr['corporate_id']) ? true : false;
17242    
17243            $this->Corporate->openDBReplica();
17244            $corporateData = $this->Corporate->find('first', array(
17245                    'fields' => array('payment_method'),
17246                    'conditions' => array('id' => $userDataArr['corporate_id']),
17247                    'recursive' => -1
17248            ));
17249            $this->Corporate->closeDBReplica();
17250    
17251            $corporateData = $corporateData ? $corporateData['Corporate'] : null;
17252
17253        // if corporate user
17254        if ($corporateUser && $corporateData && $corporateData['payment_method'] == 1) {
17255            
17256            // NJ-28462 Organize the re-enrollment behavior after corporate plan end From bug ticket
17257            $cpData = $this->getCorporatePaymentPlan($userDataArr);
17258            if (!$cpData) {
17259                return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
17260            }
17261            $corporateIndiUser = $cpData;
17262
17263            // check if corporate user retain as individual plan using new card
17264            if (!$retainIndiPlan = isset($requestQuery['retainIndiPlan']) ? $requestQuery['retainIndiPlan'] : null) {
17265                // check if corporate user retain as individual plan using existing card
17266                $retainIndiPlan = isset($requestData['ZPaymentFullLogs']['retainIndiPlan']) ? $requestData['ZPaymentFullLogs']['retainIndiPlan'] : null;
17267            }
17268
17269            if ($retainIndiPlan) {
17270                // get corporate user individual payment plan data
17271                if ($corporateChargeMemData = $this->memcache->get('mobappCreditChargeCorporateData_' . $userDataArr['id'])) {
17272                    $formType = myTools::getCorporateCompanyCardFormType($corporateChargeMemData['paymentPlanId']);
17273                    $amount = (int)$corporateChargeMemData['paymentAmount'];
17274                    $fAmount = $corporateChargeMemData['fAmount'];
17275                }
17276            }
17277        }
17278        // - set receivable 
17279        $receivablePayment =  $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id']);
17280
17281        // get live lesson payment receivable
17282        $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('appreciation_data.payment_element_type'));
17283
17284        // get live lesson payment receivable
17285        $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('payment_element_type.live'));
17286
17287        $corporateTaxRate = Configure::read('tax.increase');
17288
17289        $mobappCorpIndividualData = array(
17290            'apiToken' => $apiToken,
17291        );
17292        if ($corporateIndiUser) {
17293            $this->corpIndividualData($userDataArr, $mobappCorpIndividualData);
17294        }
17295        $annualDiscountOptionData = $this->DiscountOptionsPrice->getPaymentData(['currencyCode' => $userDataArr['currency_code'], 'discountOptionId' => Configure::read('discount_option.annual.plan_id')]);
17296        $annualDiscountOptionAmount = 0;
17297
17298        // - check if there is annual discount option data
17299        if ($annualDiscountOptionData) {
17300            unset($annualDiscountOptionData['contract_start']);
17301            $annualDiscountOptionData += [
17302                'dosh_event' => Configure::read('discount_option.dosh_event.annual_discount'),
17303                'dosh_status' => Configure::read('discount_option.dosh_status.monthly_discount')
17304            ];
17305
17306            $annualDiscountOptionAmount = $annualDiscountOptionData['amount'];
17307        }
17308
17309        $monthlyPriceWithAnnualDiscount = $paymentData['amount'] - $annualDiscountOptionAmount;
17310        $monthlyPriceWithAnnualDiscountNoTax = $monthlyPriceWithAnnualDiscount / $corporateTaxRate;
17311        $monthlyPriceWithAnnualDiscountNoTax = round($monthlyPriceWithAnnualDiscountNoTax);
17312
17313        $this->set('enableAnnualDiscountOption', $annualDiscountOptionData ? true : false);
17314        $this->set('annualDiscountOptionAmount', myTools::formatAmount($annualDiscountOptionAmount));
17315        $this->set('monthlyPriceWithAnnualDiscount', myTools::formatAmount($monthlyPriceWithAnnualDiscount));
17316        $this->set('monthlyPriceWithAnnualDiscountNoTax', myTools::formatAmount($monthlyPriceWithAnnualDiscountNoTax));
17317
17318        // check if post
17319        if ($this->request->is('post')) {
17320            $data = $this->request->data;
17321
17322            // NJ-32737
17323            $couponData = $this->Session->read('apply_coupon_usage_data');
17324
17325            if (
17326                $annualDiscountOptionData &&
17327                isset($data['ZPaymentFullLogs']['payment_plan_type']) &&
17328                $data['ZPaymentFullLogs']['payment_plan_type'] == Configure::read('register_plan_types.premium_with_annual_discount_option')
17329            ) {
17330                $userDataArr['paymentAmount'] -=  $annualDiscountOptionData['amount'];
17331                $data['discountOption'] = $userDataArr['discountOption'] = $annualDiscountOptionData;
17332            }
17333
17334            $isLitePlanFlg = false;
17335            $isChocottoPlanFlg = false;
17336
17337            if (
17338                isset($data['ZPaymentFullLogs']['payment_plan_type']) && 
17339                !$corporateIndiUser
17340            ) {
17341
17342                $isLitePlan = $isLitePlanFlg = ((int) $data['ZPaymentFullLogs']['payment_plan_type']  == 1) ? true : false;
17343                $isChocottoPlan = $isChocottoPlanFlg = ((int) $data['ZPaymentFullLogs']['payment_plan_type']  == Configure::read('register_plan_types.chocotto'));
17344
17345                if ($isLitePlan) {
17346                    $_plan_id = Configure::read('payment_plans.light_plan');
17347                    $formType = myTools::getLitePlanUserFormType($_plan_id);
17348                } elseif ($isChocottoPlan) {
17349                    $_plan_id = Configure::read('payment_plans.chocotto_plan');
17350                    $formType = Configure::read('payment_credit_chocotto_force_charge');
17351                }else{
17352                    $_plan_id = Configure::read('payment_plans.premium_plan');
17353                    $formType = Configure::read('payment_credit_force_charge');
17354                }
17355
17356                // fetch light plan description
17357                $litePlanData = $this->PaymentPlanPrice->getPaymentData(array(
17358                    'currencyCode' => $userDataArr['currency_code'],
17359                    'paymentPlanId' => $_plan_id,
17360                    'logFileName' => 'card_reregister'
17361                ));
17362
17363                if (!$litePlanData) {
17364                    return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
17365                }
17366
17367                // update payment plan data 
17368                $paymentData = $litePlanData;
17369
17370                $userDataArr['paymentAmount'] = $paymentData['amount'];
17371                $userDataArr['price_id'] = $paymentData['priceId'];
17372                $userDataArr['payment_plan_id'] = $paymentData['paymentPlanId'];
17373
17374                // add reserve payment receivable
17375                $userDataArr['paymentAmount'] +=  $receivablePayment;
17376
17377                // add appreciation payment receivable
17378                $userDataArr['paymentAmount'] +=  $appreciationReceivable;
17379
17380                // add live lesson payment receivable
17381                $userDataArr['paymentAmount'] +=  $liveLessonReceivable;
17382
17383                // NJ-32737
17384                $membershipStatusIndex = UserTable::getStudentMembershipStatus($userDataArr['id']);
17385                if (in_array($membershipStatusIndex, Configure::read('allow_coupon.settlement')) &&
17386                    isset($formType) &&
17387                    in_array($formType, Configure::read('allow_coupon.settlement_form_type'))
17388                ) {
17389                    if (isset($couponData['useCouponAmount']) && $couponData['useCouponAmount'] > 0) {
17390                        if ($paymentData['amount'] >= $couponData['useCouponAmount']) {
17391                            $total_coupon_used = $couponData['useCouponAmount'];
17392                        } else {
17393                            $total_coupon_used = $paymentData['amount'];
17394                        }
17395
17396                        $userDataArr['couponUseSettlement'] = $couponData;
17397                    }
17398                }
17399                // NJ-32737-end
17400
17401                // - update form type
17402                $data['formType'] = $formType;
17403
17404                // redirect to retry page if failed to create payment transaction
17405                if (!$npt = $this->createPaymentTransaction($formType, $userDataArr)) {
17406                    return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
17407                }
17408
17409                // update payment hash , form type and money
17410                $data['ZPaymentFullLogs']['paymentHash'] = $npt['payment_hash'];
17411                $data['ZPaymentFullLogs']['money'] = $litePlanData['amount'] - $total_coupon_used;
17412                $data['ZPaymentFullLogs']['formType'] = $formType;
17413            }else{
17414                $npt = true;
17415            }
17416
17417            // redirect to paypal confirm page if payment gateway selected is paypal
17418            if ($data['payment_gateway_type'] == Configure::read('card_company.paypal')) {
17419                    $data['paymentPlanData'] = $paymentData;
17420                    $data['receivablePayment'] = $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id']);
17421                    $data['appreciationReceivable'] = $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('appreciation_data.payment_element_type'));
17422                    $data['liveLessonReceivable'] = $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('payment_element_type.live'));
17423                    $data['formType'] = $formType;
17424                    $this->memcache->set(array(
17425                        'key' => 'mobappPaypalPaymentCreditChargeData_' . $apiToken,
17426                        'value' => $data,
17427                        'expire' => 3600 // 1 hour
17428                    ));
17429                    return $this->redirect(myTools::getUrl() . '/mobapp/payment/paypal_payment_credit_charge_confirm?token=' . $apiToken);
17430            }
17431
17432            // delete payment gateway type memcache
17433            $this->memcache->delete('mobappCreditChargePaymentGatewayType_' . $apiToken);
17434
17435            $data['token'] = $apiToken;
17436            $data['ZPaymentFullLogs']['telno'] = Configure::read('credit.default_telno');
17437            $data['ZPaymentFullLogs']['clientip'] = Configure::read('ZEUS_clientip');
17438            $data['cardToken'] = $cardToken;
17439            $data['ZPaymentFullLogs']['indiCorpType'] = 1;
17440
17441            if($corporateIndiUser && isset($data['ZPaymentFullLogs']['corporatePlan']) && !$isLitePlanFlg && !$isChocottoPlanFlg) {
17442                    if($data['ZPaymentFullLogs']['corporatePlan'] == 'light') {
17443                        $getPaymentPlanId = $this->getCorporatePaymentPlan($userDataArr,array('corporate_type' => 4));
17444                        $getLightCorporateData = $this->Corporate->getCorporateLightUserMonthly(array(
17445                            'user_id' => $userDataArr['id'],
17446                            'remove_heavy_flg' => true
17447                        ));
17448                        $paymentLightAmount = isset($getLightCorporateData['total']) ? $getLightCorporateData['total'] : 0;
17449                        $basicLightFee = isset($getLightCorporateData['basic_fee']) ? $getLightCorporateData['basic_fee'] : 0;
17450                        $lessonLightFee = isset($getLightCorporateData['lesson_fee']) ? $getLightCorporateData['lesson_fee'] : 0;
17451                        $basicLightFeeWoTax = isset($getLightCorporateData['basic_fee_discounted']) ? $getLightCorporateData['basic_fee_discounted'] : 0;
17452                        $freeLightNumber = isset($getLightCorporateData['fee_charge_count']) ? $getLightCorporateData['fee_charge_count'] : 0;
17453                        $isLightFreeFlg = isset($getLightCorporateData['free_charge_flg']) ? $getLightCorporateData['free_charge_flg'] : false;
17454                        $monthlyLightFee = isset($getLightCorporateData['monthly_fee_wo_tax']) ? $getLightCorporateData['monthly_fee_wo_tax'] : 0;
17455                        $cfLightAmount = myTools::formatAmount($basicLightFeeWoTax);
17456                        $cLightRawAmount = $basicLightFeeWoTax;
17457                        $lessonLightLimit = $this->Corporate->getLessonLimit($userDataArr['corporate_id']);
17458                        $cpData = array(
17459                            'basicFee' => $basicLightFee,
17460                            'lessonFee' => $lessonLightFee,
17461                            'freeFlg' => $isLightFreeFlg,
17462                            'freeNumber' => $freeLightNumber,
17463                            'monthlyFee' => $monthlyLightFee,
17464                            'fAmount' => $cfLightAmount,
17465                            'paymentAmount' => $paymentLightAmount,
17466                            'lessonLimit' => $lessonLightLimit,
17467                            'paymentPlanId' => $getPaymentPlanId['paymentPlanId'],
17468                            'cRawAmount'    => $cLightRawAmount,
17469                            'basicFeeWoTax' => $basicLightFeeWoTax,
17470                            'priceId'        => $getPaymentPlanId['priceId']
17471                        );
17472        
17473                        $data['ZPaymentFullLogs']['indiCorpType'] = 4;
17474                    } else if($data['ZPaymentFullLogs']['corporatePlan'] == 'premium') {
17475                        $cpPremuimData = $this->getCorporatePaymentPlan($userDataArr,array('corporate_type' => 2));
17476                        
17477                        $cdrPremiumParam = array('corporateId' => $userDataArr['corporate_id'], 'corporateType' => 2);
17478                        $discountPremium = (int)$this->CorporateDiscountRate->getDiscount($cdrPremiumParam);
17479                        $cPremiumAmount = (int)$cpPremuimData['amount'] - $discountPremium;
17480                        $cPremiumRawAmount = $cPremiumAmount;
17481                        $cfPremiumAmount = myTools::formatAmount($cPremiumAmount);
17482                        $cpData = array(
17483                            'cprAmount' => $cpPremuimData['amount'],
17484                            'cprDiscount' => $discountPremium,
17485                            'paymentAmount' => $cPremiumAmount * $corporateTaxRate,
17486                            'fAmount' => $cfPremiumAmount,
17487                            'cRawAmount' => $cPremiumRawAmount,
17488                            'ppAmount' => $cpPremuimData,
17489                            'paymentPlanId' => $cpPremuimData['paymentPlanId'],
17490                            'priceId'        => $cpPremuimData['priceId']
17491                        );
17492        
17493                        $data['ZPaymentFullLogs']['indiCorpType'] = 2;
17494                    } else {
17495                        $cpStandardData = $this->getCorporatePaymentPlan($userDataArr,array('corporate_type' => 1));
17496                        $cdrStandardParam = array('corporateId' => $userDataArr['corporate_id'], 'corporateType' => 1);
17497                        $discountStandard = (int)$this->CorporateDiscountRate->getDiscount($cdrStandardParam);
17498                        $cStandardAmount = (int)$cpStandardData['amount'] - $discountStandard;
17499                        $cStandardRawAmount = $cStandardAmount;
17500                        $cfStandardAmount = myTools::formatAmount($cStandardAmount);
17501                        $cpData = array(
17502                            'cprAmount' => $cpStandardData['amount'],
17503                            'cprDiscount' => $discountStandard,
17504                            'paymentAmount' => $cStandardAmount * $corporateTaxRate,
17505                            'fAmount' => $cfStandardAmount,
17506                            'cRawAmount' => $cStandardRawAmount,
17507                            'ppAmount' => $cpStandardData,
17508                            'paymentPlanId' => $cpStandardData['paymentPlanId'],
17509                            'priceId'        => $cpStandardData['priceId']
17510                        );
17511                        $data['ZPaymentFullLogs']['indiCorpType'] = 1;
17512                    }
17513                    $data['ZPaymentFullLogs']['formType'] = $formType = myTools::getCorporateCompanyCardFormType($cpData['paymentPlanId']);
17514                    $corpIndiPrices = $this->memcache->get('mobappcorporateIndiPrices_'.$userDataArr['api_token']);
17515                    $corpIndiPrices[$data['ZPaymentFullLogs']['corporatePlan']]['plan_type'] = $data['ZPaymentFullLogs']['indiCorpType'];
17516                    $amount = (int)$corpIndiPrices[$data['ZPaymentFullLogs']['corporatePlan']]['paymentAmount'];
17517                    $fAmount = $corpIndiPrices[$data['ZPaymentFullLogs']['corporatePlan']]['fAmount'];
17518    
17519                    $this->memcache->set(array(
17520                        'key' => 'mobappCreditChargeCorporateData_' . $userDataArr['id'],
17521                        'value' => $corpIndiPrices[$data['ZPaymentFullLogs']['corporatePlan']],
17522                        'expire' => 3600 // 1 hour
17523                    ));
17524    
17525                    $corporateChargeMemData = $this->memcache->get('mobappCreditChargeCorporateData_' . $userDataArr['id']);
17526    
17527                    // corporate light
17528                    if (
17529                        $corporateChargeMemData['plan_type'] == Configure::read('corporate_type.light') &&
17530                        isset($corporateChargeMemData['lessonFee']) &&
17531                        isset($corporateChargeMemData['basicFee'])
17532                    ) {
17533                        $userDataArr['lesson_fee'] = (int)$corporateChargeMemData['lessonFee'];
17534                        $userDataArr['basic_fee'] = (int)$corporateChargeMemData['basicFee'];
17535                    // standard or premium
17536                    } else {
17537                        if (isset($corporateChargeMemData['cprAmount']) && isset($corporateChargeMemData['cprDiscount'])) {
17538                            $userDataArr['cprAmount'] = (int)$corporateChargeMemData['cprAmount'];
17539                            $userDataArr['cprDiscount'] = (int)$corporateChargeMemData['cprDiscount'];
17540                        }
17541                    }
17542    
17543                    $userDataArr['corporateSettlementType'] = Configure::read('corporate_settlement_types.force_charge_payment');
17544                    $userDataArr['paymentAmount'] = $amount;
17545                    $userDataArr['price_id'] = $cpData['priceId'];
17546                    $userDataArr['payment_plan_id'] = $cpData['paymentPlanId'];
17547                    $userDataArr['corporate_type'] = $data['ZPaymentFullLogs']['indiCorpType'];
17548                    $formType = myTools::getCorporateCompanyCardFormType($cpData['paymentPlanId']);
17549    
17550                    $membershipTypes = UserTable::getEngMembershipTypeData();
17551                    $userDataArr['statusAfter'] =  myTools::getCorporateUserMembershipStatusName($membershipTypes, $userDataArr['payment_plan_id']);
17552    
17553                    $userTable = new UserTable($userDataArr);
17554                    // add statusBefore and statusAfter if free "Trial not yet conducted"
17555                    if ($userTable->getMembershipTypeIndex() == 13) {
17556                        $userDataArr['statusBefore'] = $membershipTypes[13];
17557                        $userDataArr['statusAfter'] = myTools::getCorporateUserMembershipStatusName($membershipTypes, $userDataArr['payment_plan_id']);
17558                    }
17559
17560                    //- check chocotto camp membership
17561                    if (in_array(
17562                        $userDataArr['payment_plan_id'],
17563                        [
17564                            Configure::read('payment_plans.free_trial_chocotto'),
17565                            Configure::read('payment_plans.chocotto_plan')
17566                        ]
17567                    )) {
17568                        $userDataArr['statusAfter'] = $membershipTypes[Configure::read('membership_type_chocotto_plan_paid')];
17569                    }
17570    
17571                    if ($retainIndiPlan) {
17572                        $data['ZPaymentFullLogs']['retainIndiPlan'] = $retainIndiPlan;
17573                    }
17574    
17575                    if ($corporateIndiUser && $corporateChargeMemData) {
17576                        // save new card charge token to memcache
17577                        $this->memcache->set(array(
17578                            'key' => 'card-charge-'.$apiToken,
17579                            'value' => $cardToken,
17580                            'expire' => 3600
17581                        ));
17582                    }
17583    
17584            } // End of Check Corporate Individual
17585
17586            // NJ-25522: Skip confirm page if using 3D secure challenge
17587            $zeus3DSecureChallengeFlg = $this->memcache->get('zeus3DSecureChallengeFlg_' . $userDataArr['id']);
17588            
17589            if ($zeus3DSecureChallengeFlg) {
17590                    // unset previously set tokens
17591                    $this->unsetTokenMobapp($apiToken, 'card-charge-');
17592
17593                    $formType = isset($data['ZPaymentFullLogs']['formType']) ? $data['ZPaymentFullLogs']['formType'] : $formType;
17594
17595                    // if corporate credit charge
17596                    if (
17597                        $formType != Configure::read('payment_credit_force_charge') && 
17598                        !$isLitePlanFlg &&
17599                        !$isChocottoPlanFlg
17600                    ) {
17601                        $data['ZPaymentFullLogs']['money'] = $fAmount;
17602                    }
17603
17604                    if($corporateIndiUser) {
17605                        $data['ZPaymentFullLogs']['paymentHash'] = $this->memcache->get('indiCorpPaymentHash_'.$userDataArr['id']);
17606                    }
17607                     
17608                    $totalReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id']) + $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('appreciation_data.payment_element_type')) + $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('payment_element_type.live'));
17609
17610                    $data['ZPaymentFullLogs']['money'] += $totalReceivable;
17611                    $data['ZPaymentFullLogs']['money'] -= $annualDiscountOptionAmount;
17612
17613                    $this->Session->write('mobapp_show_welcome_back_modal',true);
17614                    //process zeus card
17615                    $this->zeus_card_process_mobapp(array(
17616                        'data' => $data,
17617                        'form_type' => $formType,
17618                        'referrer' => array('controller' => 'Payment', 'action' => 'mobapp_credit_charge', '?' => array('token' => $apiToken)),
17619                        'api_token' => $apiToken
17620                    ));
17621
17622            }
17623
17624            if(!$zeus3DSecureChallengeFlg && $corporateIndiUser) {
17625                $data['userApiToken'] = $apiToken;
17626                $data['userData'] = $userDataArr;
17627                $corpIndiPT = $this->createCorporateIndividualPayment($data);
17628                $data['ZPaymentFullLogs']['paymentHash'] = $corpIndiPT['paymentHash'];
17629                $data['ZPaymentFullLogs']['money'] = $corpIndiPT['paymentAmount'];
17630            }
17631
17632            // delete memcache if exist
17633            if ($this->memcache->get($memKey)) {
17634                $this->memcache->delete($memKey);
17635            }
17636
17637            // set memcache
17638            $this->memcache->set(array(
17639                'key' => $memKey,
17640                'value' => $data,
17641                'expire' => 3600
17642            ));
17643
17644            return $this->redirect(myTools::getUrl() . '/payment/mobapp_credit_charge_confirm'.$urlParams);
17645        
17646        } else {
17647            // delete payment gateway type memcache
17648            $this->memcache->delete('mobappCreditChargePaymentGatewayType_' . $apiToken);
17649
17650            $this->set('data', $this->memcache->get($memKey));
17651        }
17652
17653        // if not retain indi plan
17654        if (!$corporateIndiUser) {
17655            $userDataArr['paymentAmount'] = $paymentData['amount'];
17656            $userDataArr['price_id'] = $paymentData['priceId'];
17657            $userDataArr['payment_plan_id'] = $paymentData['paymentPlanId'];
17658
17659            $data['ZPaymentFullLogs']['formType'] = $formType;
17660
17661            // add reserve payment receivable
17662            $userDataArr['paymentAmount'] +=  $receivablePayment;
17663
17664            // add appreciation payment receivable
17665            $userDataArr['paymentAmount'] +=  $appreciationReceivable;
17666
17667            // add live lesson payment receivable
17668            $userDataArr['paymentAmount'] +=  $liveLessonReceivable;
17669
17670            // redirect to retry page if failed to create payment transaction
17671            if (!$pt = $this->createPaymentTransaction($formType, $userDataArr)) {
17672                return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
17673            }
17674
17675            $data['ZPaymentFullLogs']['paymentHash'] = $pt['payment_hash'];
17676
17677        }
17678
17679        // delete memcache if exist
17680        if ($this->memcache->get($memKey)) {
17681            $this->memcache->delete($memKey);
17682        }
17683
17684        // set memcache
17685        $this->memcache->set(array(
17686            'key' => $memKey,
17687            'value' => $data,
17688            'expire' => 3600
17689        ));
17690
17691        // NJ-32737
17692        $this->setCouponUseData($userDataArr['id'], $userDataArr['currency_code']);
17693
17694        // set the view vars
17695        $this->set('cardToken', $cardToken);
17696        $this->set('apiToken', $apiToken);
17697        $this->set('zeusTransactionFlag', true);
17698        $this->set('corporateIndiUser',$corporateIndiUser);
17699        $this->set('monthlyPrice', $amount);
17700        $this->set('monthylyPriceNoTax', myTools::formatAmount($paymentData['amountConstTaxDeducted']));
17701        $this->set('monthlyPriceSymbol',myTools::getCurrencySymbol($userDataArr['currency_code']));
17702        $this->set('amount', $amount);
17703        $this->set('fAmount', $fAmount);
17704        $this->set('paymentHash', isset($pt['payment_hash']) ? $pt['payment_hash'] : "");
17705        $this->set('retainIndiPlan', $retainIndiPlan);
17706        $this->set('failURLReferer', myTools::getUrl() . "/mobapp/payment/credit_charge?token=" . $apiToken);
17707        $this->render(myTools::getDeviceUrl() . 'Payment/credit_charge_form');
17708    }
17709
17710    /**
17711     * @api {post} /mobapp/payment_wp_credit_charge/:token mobapp_wp_credit_charge()
17712     * @apiName mobapp_wp_credit_charge
17713     * @apiGroup Payment
17714     * @apiDescription This endpoint is used to charge the user's credit card.
17715     * 
17716     * @apiParam {String} token User's token
17717     * 
17718     * @apiBody {Number} cardType 0 for existing card, 1 for new card
17719     * 
17720     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/wp_credit_charge_form?token={{token}} if cardType is 1
17721     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/wp_credit_charge_confirm?token={{token}} if cardType is 0
17722     * 
17723     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if there is an error
17724     * 
17725     * @apiSuccessExample Success Response Existing card:
17726     * Redirects to {{ENV}}/mobapp/payment/wp_credit_charge_confirm?token={{token}}
17727     * 
17728     * @apiSuccessExample Success Response New card:
17729     * Redirects to {{ENV}}/mobapp/payment/wp_credit_charge_form?token={{token}}
17730     * 
17731     * @apiErrorExample Error Response:
17732     * Redirects to {{ENV}}/mobapp/retrypage
17733     * 
17734     * @apiSampleRequest off
17735     */
17736    public function mobapp_wp_credit_charge() {
17737
17738        if ($this->Session->read('credit_skip_to_confirmation')) {
17739            $this->Session->delete('credit_skip_to_confirmation');
17740        }
17741
17742
17743        $this->blockWithdrawnSapuriToS('mobapp');
17744        $this->disablePageForSapuri('mobapp');
17745        
17746        // set variables
17747        $logFileName = 'card_charge';
17748        $formType = Configure::read('payment_credit_force_charge');
17749        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType));
17750        $userData = $userData['User'];
17751        $this->layout = "mobapp";
17752        $this->response->disableCache();
17753        $apiToken = $userData['api_token'];
17754        $currencyCode = $userData['currency_code'];
17755        $memKey = "credit_charge_{$userData['id']}_{$currencyCode}";
17756        $cardType = $this->memcache->get($memKey);
17757        $cardType = isset($cardType) ? $cardType : 0;
17758
17759        $this->restrictForTrialNotConducted($userData, myTools::getMobappToken($_GET));
17760        // get monthly price
17761        $amount = $this->PaymentPlanPrice->getMonthlyPrice(array(
17762            'currencyCode' => $currencyCode,
17763            'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
17764            'logFileName' => $logFileName
17765        ));
17766
17767        if (!isset($amount)) {
17768            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.myTools::getMobappToken($_GET));
17769        }
17770
17771        $isFamilyPlanBefore = PaymentTable::checkIfFamilyPlan(
17772            $userData['id'],
17773            $userData['hash16'],
17774            array(
17775                Configure::read('payment_credit_family_free'),
17776                Configure::read('payment_credit_family_monthly_payment')
17777            )
17778        );
17779
17780        // if complimentary plan
17781        if ($comPlanUser = isset($userData['com_plan_user']) && $userData['com_plan_user'] ? $userData['com_plan_user'] : false) {
17782            $this->set('cPlan', $comPlanUser);
17783        }
17784
17785        // redirect to form page if child and parent unsubscribed
17786        if ( 
17787            (empty($userData['card_company']) && empty($userData['card_brand']) && empty($userData['card_token']) && empty($userData['card_number'])) ||
17788            ($userData['card_brand'] == 'AFTEE2' && empty($userData['card_company']))
17789        ) {
17790            $this->memcacheCardType(array(
17791                'key' => $memKey,
17792                'value' => array('cardType' => $cardType)
17793            ));
17794            $this->redirect(myTools::getUrl() . "/mobapp/payment/wp_credit_charge_form".myTools::getMobappToken($_GET)."&com_plan_user={$comPlanUser}");
17795        }
17796
17797        if ($this->request->is('post')) {
17798            $cardType = $this->request->data['cardType'];
17799
17800            // memcache card type value
17801            $this->memcacheCardType(array(
17802                'key' => $memKey,
17803                'value' => $cardType
17804            ));
17805
17806            // redirect to hosted page if using new card ($cardType = 1)
17807            if ($cardType) {
17808                 $this->redirect(myTools::getUrl() . "/mobapp/payment/wp_credit_charge_form".myTools::getMobappToken($_GET)."&com_plan_user={$comPlanUser}");
17809            // redirect to confirm page if using existing card ($cardType = 0)
17810            } else {
17811
17812                // - NJ-23812: write session to skip and auto charge 
17813                $this->Session->write('credit_skip_to_confirmation',true);
17814
17815                $this->redirect(myTools::getUrl() . "/mobapp/payment/wp_credit_charge_confirm?token=$apiToken");
17816            }
17817        }
17818
17819        // // check if there is error
17820        // if ($error = $this->memcache->get('card_charge_error_'. $apiToken)) {
17821        //     $this->memcache->delete('card_charge_error_'. $apiToken);
17822        //     $this->set('error', $error);
17823        // }
17824
17825        // set view variables
17826        $this->set('cardLogo', myTools::getWorldpayCardLogo($userData['card_brand']));
17827        if(
17828            (is_null($userData['card_number']) || is_null($userData['card_brand'])) &&
17829            ($isFamilyPlanBefore)
17830        ){
17831            $cardType = 1; // set as default
17832        }
17833        $this->set('cardType', $cardType);
17834        $this->set('apiToken', $apiToken);
17835        $this->set('user', $userData);
17836        $this->set('title_for_layout', '再入会');
17837        $this->render(myTools::getDeviceUrl() . 'Payment/wp_credit_charge');
17838
17839        // NJ-32737
17840        $this->setCouponUseData($userData['id'], $userData['currency_code']);
17841
17842        // NJ-23812 redirect to change form
17843        return  $this->redirect(myTools::getUrl() . "/mobapp/payment/wp_credit_charge_form?token={$apiToken}&com_plan_user={$comPlanUser}");
17844    }
17845
17846    /**
17847     * @api {get} /mobapp/payment/wp_credit_charge_form/:token mobapp_wp_credit_charge_form()
17848     * @apiName mobapp_wp_credit_charge_form
17849     * @apiGroup Payment
17850     * @apiDescription This endpoint is used to process the form for charging the user's credit card.
17851     * 
17852     * @apiParam {String} token User's token
17853     * @apiParam {Boolean} [com_plan_user] Indicates if user is a complimentary plan user
17854     * 
17855     * @apiSuccess {View} Redirect Redirects to {{ENV}}/user/mobapp/close?token={{token}}&type=special_complimentary_plan if user is a complimentary plan user
17856     * @apiSuccess {View} Redirect Redirects to {{ENV}}/user/mobapp/close?token={{token}}&type=premium_plan_paid if user is not a complimentary plan user
17857     * 
17858     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if there is an error
17859     * 
17860     * @apiSuccessExample Success Response Complimentary Plan User:
17861     * Redirects to {{ENV}}/user/mobapp/close?token={{token}}&type=special_complimentary_plan
17862     * 
17863     * @apiSuccessExample Success Response Premium Plan User:
17864     * Redirects to {{ENV}}/user/mobapp/close?token={{token}}&type=premium_plan_paid
17865     * 
17866     * @apiErrorExample Error Response:
17867     * Redirects to {{ENV}}/mobapp/retrypage
17868     * 
17869     * @apiSampleRequest off
17870     */
17871    public function mobapp_wp_credit_charge_form() {
17872
17873        if ($this->Session->read('credit_skip_to_confirmation')) {
17874            $this->Session->delete('credit_skip_to_confirmation');
17875        }
17876
17877        $this->blockWithdrawnSapuriToS('mobapp');
17878        $this->disablePageForSapuri('mobapp');
17879        // set variables
17880        $logFileName = 'card_charge';
17881        $formType = Configure::read('payment_credit_force_charge');
17882        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType));
17883        $apiToken = $userData['User']['api_token'];
17884        $user = $userData['User'];
17885        $this->layout = "mobapp";
17886        $this->response->disableCache();
17887
17888        // - NJ-23812: support 
17889        $memKey = "credit_charge_{$userData['id']}_{$currencyCode}";
17890        $cardType = $this->memcache->get($memKey);
17891        $cardType = isset($cardType) ? $cardType : 0;
17892        // - NJ-23812- support end
17893
17894        // check if allowed aftee
17895        $this->checkAfteeSupported($userData['User']);
17896
17897        $this->setPerMonthSymbol($user['native_language2'], true);
17898
17899        // set view variables
17900        $this->set('pmtValue', 'payment');
17901        $this->set('apiToken', $apiToken);
17902        $this->set('logFileName', $logFileName);
17903        $this->set('worldpayFlg', true);
17904        $this->set('memKeyError', 'card_charge_error_'.$apiToken);
17905        $this->set('referrer', urlencode(myTools::getUrl()."/mobapp/payment/wp_credit_charge_form?token={$apiToken}"));
17906
17907        if ($this->Session->read('mobapp_show_welcome_back_modal')) {
17908            $this->Session->delete('mobapp_show_welcome_back_modal');
17909        }
17910
17911
17912        // - NJ-23812 : support start 
17913
17914        // check if there is error
17915        if ($error = $this->memcache->get('card_charge_error_'. $apiToken)) {
17916            $this->memcache->delete('card_charge_error_'. $apiToken);
17917            $this->set('error', $error);
17918        }
17919    
17920        
17921
17922        $isCardRegistered = (!empty($user['card_brand']) && !empty($user['card_number'])) ? true : false;
17923        $comPlanUser = (isset($user['com_plan_user']) && $user['com_plan_user']) ? $user['com_plan_user'] : false;
17924
17925        $isFamilyPlanBefore = PaymentTable::checkIfFamilyPlan(
17926            $user['id'],
17927            $user['hash16'],
17928            array(
17929                Configure::read('payment_credit_family_free'),
17930                Configure::read('payment_credit_family_monthly_payment')
17931            )
17932        );
17933        if(
17934            (is_null($user['card_number']) || is_null($user['card_brand'])) &&
17935            ($isFamilyPlanBefore)
17936        ){
17937            $cardType = 1; // set as default
17938        }
17939
17940        // - set for the payment plan detais 
17941        $this->setPaymentPlanDetails($user,Configure::read('payment_plans.premium_plan'),$logFileName);
17942
17943        // set view variables
17944        $this->set('isCardRegistered',$isCardRegistered);
17945        $this->set('cPlan', $comPlanUser);
17946        $this->set('user', $user);
17947        $this->set('cardLogo', myTools::getWorldpayCardLogo($user['card_brand']));
17948        $this->set('cardType', $cardType);
17949        $this->set('apiToken', $apiToken);
17950        $this->set('cardNumber', $user['card_number']);
17951        $this->set('cardBrand', $user['card_brand']);
17952        // - NJ-23812 : support end
17953
17954        // NJ-32737
17955        $this->setCouponUseData($user['id'], $user['currency_code']);
17956
17957        // if complimentary plan user
17958        if (isset($this->request->query['com_plan_user']) && $this->request->query['com_plan_user']) {
17959            $addWelcomeModal = "&re_enrolled=1";
17960            $this->set('successUrl', urlencode(myTools::getUrl()."/user/mobapp/close?token={$apiToken}&type=special_complimentary_plan{$addWelcomeModal}"));
17961        } else {
17962            $addWelcomeModal = "&re_enrolled=1";
17963            $this->set('successUrl', urlencode(myTools::getUrl()."/user/mobapp/close?token={$apiToken}&type=premium_plan_paid{$addWelcomeModal}"));
17964        }
17965
17966        $this->set('title_for_layout', '再入会');
17967        $this->set('formType', $formType);
17968        $this->render(myTools::getDeviceUrl() . 'Payment/wp_credit_charge_form');
17969    }
17970    /**
17971     * @api {post} /mobapp/payment/wp_credit_charge_confirm/:token mobapp_wp_credit_charge_confirm()
17972     * @apiName mobapp_wp_credit_charge_confirm
17973     * @apiGroup Payment
17974     * @apiDescription This endpoint is used to confirm the charging of the user's credit card.
17975     * 
17976     * @apiParam {String} token User's token
17977     * 
17978     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/close?token=$apiToken&type=special_complimentary_plan".$addWelcomeModal if user is a complimentary plan user
17979     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/close?token=$apiToken&type=premium_plan_paid".$addWelcomeModal if user is not a complimentary plan user
17980     * 
17981     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if there is an error
17982     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/payment/wp_credit_charge?token= if direct payment response is not authorized
17983     * 
17984     * @apiSuccessExample Success Response Complimentary Plan User:
17985     * Redirects to {{ENV}}/mobapp/close?token=$apiToken&type=special_complimentary_plan".$addWelcomeModal
17986     * 
17987     * @apiSuccessExample Success Response Premium Plan User:
17988     * Redirects to {{ENV}}/mobapp/close?token=$apiToken&type=premium_plan_paid".$addWelcomeModal
17989     * 
17990     * @apiErrorExample Error Response If there is an arror:
17991     * Redirects to {{ENV}}/mobapp/retrypage
17992     * 
17993     * @apiErrorExample Error Response Direct Payment Response Not Authorized:
17994     * Redirects to {{ENV}}/mobapp/payment/wp_credit_charge?token= with error message
17995     * 
17996     * @apiSampleRequest off
17997     */
17998    public function mobapp_wp_credit_charge_confirm() {
17999
18000        // NJ-23812
18001        $readSkipConfirmation = $this->Session->read('credit_skip_to_confirmation');
18002        if ($readSkipConfirmation) {
18003            $this->Session->delete('credit_skip_to_confirmation');
18004        }
18005
18006        // set variables
18007        $logFileName = 'card_charge';
18008        $formType = Configure::read('payment_credit_force_charge');
18009        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType));
18010        $this->layout = "mobapp";
18011        $this->response->disableCache();
18012        $userData = $userData['User'];
18013        $currencyCode = $userData['currency_code'];
18014        $userId = $userData['id'];
18015        $apiToken = $userData['api_token'];
18016        $memKey = "credit_charge_{$userId}_{$currencyCode}";
18017        $urlParams = myTools::getMobappToken($_GET);
18018
18019        // get payment data
18020        $pData = $this->PaymentPlanPrice->getPaymentData(array(
18021            'currencyCode' => $currencyCode,
18022            'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
18023            'logFileName' => $logFileName
18024        ));
18025
18026        // redirect to retry page if premium plan payment not supported
18027        if (!$pData) {
18028            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
18029        }
18030
18031        $userData['com_plan_user'] = ($userData['payment_plan_id'] == Configure::read('payment_plans.complimentary_plan')) ? true : false;
18032        $userData['payment_plan_id'] = $pData['paymentPlanId'];
18033        $userData['price_id'] = $pData['priceId'];
18034
18035        $currency_before = $userData['currency_code'];
18036        $plan_before = $userData['payment_plan_id'];
18037
18038        $readSkipConfirmation = true;//auto charge and skip confirmation
18039
18040        if ($this->request->is('post') || $readSkipConfirmation) {
18041
18042            // get reserve payment receivable
18043            $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userId);
18044
18045            // get appreciation payment receivable
18046            $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('appreciation_data.payment_element_type'));
18047
18048            // get live lesson payment receivable
18049            $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.live'));
18050
18051            // add force charge payment, receivable payment amount and live lesson payment amount
18052            $totalAmount = $pData['amount'] + $receivablePayment + $appreciationReceivable + $liveLessonReceivable;
18053
18054            $paymentMethodType = myTools::getWPPaymentMethodType($userData['card_brand'], 'payment');
18055            $merchantCode = myTools::getWPMerchantCode($paymentMethodType);
18056            $paymentMethod = explode('_', $paymentMethodType);
18057            $paymentMethod = isset($paymentMethod[0]) ? $paymentMethod[0] : null;
18058            $orderCode = myTools::generateOrderCode($userId);
18059            $currencyExponents = Configure::read('worldpay.currency_exponents');
18060            $exponent = $currencyExponents[$currencyCode];
18061
18062            // NJ-32737
18063            $couponData = $this->Session->read('apply_coupon_usage_data');
18064            $membershipStatusIndex = UserTable::getStudentMembershipStatus($userData['id']);
18065            if (in_array($membershipStatusIndex, Configure::read('allow_coupon.settlement')) &&
18066                isset($formType) &&
18067                in_array($formType, Configure::read('allow_coupon.settlement_form_type'))
18068            ) {
18069                if (isset($couponData['useCouponAmount']) && $couponData['useCouponAmount'] > 0) {
18070                    if ($totalAmount >= $couponData['useCouponAmount']) {
18071                        $totalAmount -= $couponData['useCouponAmount'];
18072
18073                    } else {
18074                        $totalAmount = 0;
18075
18076                    }
18077
18078                    $userData['couponUseSettlement'] = $couponData;
18079                }
18080            }
18081            // NJ-32737-end
18082
18083            // get total amount with checking currency exponent
18084            $totalAmountArr = myTools::wpGetAmount($exponent, $totalAmount);
18085            $ncAmount = $totalAmountArr['ncAmount'];
18086            $wpAmount = $totalAmountArr['wpAmount'];
18087
18088            $wpData = array(
18089                'cardToken' => $userData['card_token'],
18090                'merchantCode' => $merchantCode,
18091                'paymentHash' => $orderCode,
18092                'wpPaymentAmount' => $wpAmount
18093            );
18094
18095            // set payment amount
18096            $userData['paymentAmount'] = $ncAmount;
18097
18098            // create payment transaction
18099            if (!$pt = $this->createPaymentTransaction($formType, $userData, $wpData)) {
18100                $this->log(__METHOD__ .' Failed to save payment transaction. Params --> ' . json_encode($wpData), $logFileName);
18101                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to save payment transaction. Params --> ' . json_encode($wpData), 'error');
18102                return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
18103            }
18104
18105            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - After save payment transaction. Params --> ' . json_encode($wpData), 'error');
18106            
18107            // if aftee payment
18108            if ($userData['card_company'] == Configure::read('card_company.aftee') || ($userData['card_brand'] == "AFTEE" && !empty($userData['aftee_transaction_identifier']))) {
18109
18110                if (!class_exists('AfteePaymentService')) {
18111                    App::uses('AfteePaymentService','Lib');
18112                }
18113                $afteeService = new AfteePaymentService();
18114                $afteeChecksumData = array(
18115                    'shopItemId' => "AFTEE" . $formType,
18116                    'itemName' => 'CreditForceChargeUsingExistingCard',
18117                    'itemPrice' => $totalAmount,
18118                    'itemCount' => 1,
18119                    'customerPhoneNumber' => $userData['phone_number'],
18120                    'customerEmail' => $userData['email'],
18121                    'shopTransactionNo' => $orderCode,
18122                    'userID' =>  $userData['id']
18123                );
18124                $checksum = $afteeService->generateChecksum($afteeChecksumData, false);
18125                $afteeData = array(
18126                    'authentication_token' => $userData['card_token'],
18127                    'related_id' => $userData['aftee_transaction_identifier'],
18128                    'checksum' => $checksum['checksum'],
18129                    'shop_transaction_no' => $orderCode,
18130                    'transaction_options' => array(1)
18131                );
18132        
18133                $afteePaymentData = array_merge($afteeData, $checksum['settlementData']);
18134    
18135                // aftee execute payment
18136                $receivableResult = $afteeService->directPayment($afteePaymentData);
18137                $checkRes = json_decode($receivableResult, true);
18138
18139
18140                if ( isset($checkRes['object']) && $checkRes['object'] == 'transaction') {
18141                    $prPaymentSuccess = true;
18142                } else if ( !array_key_exists("object", $checkRes) || (isset($checkRes['object']) && $checkRes['object'] == 'error')) {
18143                    $prPaymentSuccess = false;
18144                }
18145
18146                // set user model
18147                $uModel = $this->User;
18148                $dataSource = $uModel->getDataSource();
18149                $dataSource->begin();
18150
18151                $afteeTransactionIdentifier = isset($checkRes['id']) && !empty($checkRes['id']) ? $checkRes['id'] : NULL;
18152                if (isset($checkRes['related_transaction']) && !empty($checkRes['related_transaction'])) {
18153                    $afteeTransactionIdentifier = $checkRes['related_transaction'];
18154                }
18155                $orderCode = isset($checkRes['shop_transaction_no']) && !empty($checkRes['shop_transaction_no']) ? $checkRes['shop_transaction_no'] : NULL;
18156                $checkRes['OrderCode'] = $orderCode;
18157
18158                // payment transaction additional data
18159                $checkRes['OrderCode'] = $orderCode;
18160                $checkRes['authentication_token'] = $userData['card_token'];
18161                $checkRes['customer']['phone_number'] = $userData['phone_number'];
18162
18163                // process payment data
18164                if ($prPaymentSuccess) {
18165                    $afteeParams = array(
18166                        'data' => $checkRes,
18167                        'ptData' => $pt,
18168                        'logFileName' => $logFileName,
18169                        'dataSource' => $dataSource,
18170                        'amount' => $pData['amount'],
18171                        'userData' => $userData,
18172                        'receivablePayment' => $receivablePayment,
18173                        'appreciationReceivable' => $appreciationReceivable,
18174                        'liveLessonReceivable' => $liveLessonReceivable,
18175                        'transactionIdentifier' => $afteeTransactionIdentifier,
18176                        'aftee' => 1
18177                    );
18178    
18179                    $this->processAfteePayment($afteeParams);
18180                }
18181
18182                // update payment transaction
18183                $updateData = array(
18184                    'id' => $pt['id'],
18185                    'fields' => array(
18186                        'status' => $prPaymentSuccess,
18187                        'response_text' => array('aftee_directPayment_response' => $receivableResult))
18188                );
18189
18190                // update payment transaction
18191                $this->PaymentTransaction->updateAfteePaymentTransaction($updateData);
18192
18193
18194                // redirect to payment_credit_charge with error display if direct payment response is not authorised
18195                if (!$prPaymentSuccess) {
18196                    if (!class_exists('myMemcached')) {
18197                        App::uses('myMemcached', 'Lib');
18198                    }
18199                    $memKeyError = 'card_charge_error_' . $apiToken;
18200                    $memerror = __('トランザクションを完了できません。 もう一度お試しください。');
18201                    $memcached = new myMemcached();
18202                    $memcached->set(array(
18203                        'key' => $memKeyError,
18204                        'value' => $memerror,
18205                        'expire' => 3600 // 1 hour
18206                    ));
18207                    return $this->redirect(myTools::getUrl() . '/mobapp/payment/wp_credit_charge?token='.$apiToken);
18208                }
18209
18210
18211            // default worldpay payment
18212            } else {
18213
18214                $wpData = array(
18215                    'merchantCode' => $merchantCode,
18216                    'orderCode' => $orderCode,
18217                    'description' => 'Credit Force Charge Using Existing Card',
18218                    'currencyCode' => $currencyCode,
18219                    'exponent' => $exponent,
18220                    'amount' => $wpAmount,
18221                    'cardToken' => $userData['card_token'],
18222                    'email' => $userData['email'],
18223                    'authenticatedShopperId' => $userId,
18224                    'xmlName' => 'direct_payment_with_token',
18225                    'shopperIpAddress' => $_SERVER["REMOTE_ADDR"],
18226                    'wpTransactionIdentifier' => $userData['wp_transaction_identifier'],
18227                    'paymentMethod' => $paymentMethod
18228                );
18229                
18230                $result = wpPaymentService::directPayment($wpData);
18231
18232                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - directPayment result --> ' . json_encode($result), 'error');
18233
18234                $updateData = array(
18235                    'id' => $pt['id'],
18236                    'fields' => array('response_text' => array('directPayment_response' => $result)),
18237                    'logFileName' => $logFileName
18238                );
18239
18240                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - before updatePaymentTransaction result --> ' . json_encode($updateData), 'error');
18241
18242                // update payment transaction direct response.
18243                $this->updatePaymentTransaction($updateData);
18244
18245                // redirect to wp_credit_charge with error display if direct payment response is not a
18246                if (!myTools::checkIfWPPaymentResponseIsAuthorised($result)) {
18247                    $params = array(
18248                        'apiToken' => $apiToken,
18249                        'wpResponse' => $result,
18250                        'memKey' => 'card_charge_error_' . $apiToken
18251                    );
18252                    myTools::parseAndSetWPErrorResponse($params);
18253                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - WP Payment not authorised --> ' . json_encode($params), 'error');
18254                    return $this->redirect(myTools::getUrl() . '/mobapp/payment/wp_credit_charge?token='.$apiToken);
18255                }
18256            }
18257
18258            //    NC-7644 Add code reward for re-enroolling with the campaign code
18259            $this->addCoinRewardForReenroll($userData);
18260            
18261            // Teacher Perks : Student re-enroll
18262            ClassRegistry::init('TeacherPerksAccount')->reEnroll(['user_id' => $userData['id']]);
18263
18264            // delete memcache
18265            if ($this->memcache->get($memKey)) {
18266                $this->memcache->delete($memKey);
18267            }
18268            $addWelcomeModal = "&re_enrolled=1";
18269            return $this->redirect(myTools::getUrl() . "/mobapp/close?token=$apiToken&type=premium_plan_paid".$addWelcomeModal);
18270        }
18271
18272        // set view variables
18273        $this->set('cardLogo', myTools::getWorldpayCardLogo($userData['card_brand']));
18274        $this->set('apiToken', $apiToken);
18275        $this->set('cardBrand', $userData['card_brand']);
18276        $this->set('cardNumber', $userData['card_number']);
18277        $this->set('amount', $pData['amount']);
18278        $this->set('fAmount', $pData['fAmount']);
18279        $this->render(myTools::getDeviceUrl() . 'Payment/wp_credit_charge_confirm');
18280    }
18281    /**
18282     * @api {post} /mobapp/payment/credit_charge_confirm/:token 
18283     * @apiName mobapp_credit_charge_confirm
18284     * @apiGroup Payment
18285     * @apiDescription This endpoint is used to confirm the charging of the user's credit card.
18286     * 
18287     * @apiParam {String} token User's token
18288     * 
18289     * @apiBody {String} apiToken The API token.
18290     * @apiBody {String} cardToken The card token.
18291     * @apiBody {Object} ZPaymentFullLogs The payment full logs data.
18292     * @apiBody {Number} ZPaymentFullLogs.formType The form type. Set to 2 for force charge
18293     * @apiBody {Number} ZPaymentFullLogs.payment_plan_type The payment plan type.
18294     * @apiBody {Number} ZPaymentFullLogs.money The amount of money.
18295     * @apiBody {String} ZPaymentFullLogs.paymentHash The payment hash.
18296     * @apiBody {Object} discountOption The discount option data, if available.
18297     * @apiBody {Number} discountOption.amount The amount of the discount.
18298     * 
18299     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/close if payment is successful
18300     * 
18301     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if there is an error
18302     * @apiError {View} Redirect Redirects to {{ENV}}//mobapp/payment/failure_settlement if payment is not successful
18303     * 
18304     * @apiExample {json} Example usage:
18305     * {
18306     *       "apiToken": "api_token_12345",
18307     *       "cardToken": "card_token_12345",
18308     *       "ZPaymentFullLogs": {
18309     *             "formType": 2,
18310     *             "payment_plan_type": 1,
18311     *             "money": 1000,
18312     *             "paymentHash": "payment_hash_12345"
18313     *       },
18314     *       "discountOption": {
18315     *             "amount": 200
18316     *       }
18317      * }
18318     * 
18319     * @apiSuccessExample Success Response:
18320     * Redirects to {{ENV}}/mobapp/close
18321     * 
18322     * @apiErrorExample Error Response If there is an error:
18323     * Redirects to {{ENV}}/mobapp/retrypage
18324     * 
18325     * @apiErrorExample Error Response Payment Not Successful:
18326     * Redirects to {{ENV}}//mobapp/payment/failure_settlement
18327     * 
18328     * @apiSampleRequest off
18329     */
18330    public function mobapp_credit_charge_confirm() {
18331        $this->layout = 'mobapp';
18332        $formType = Configure::read('payment_credit_force_charge');
18333        $userData = $this->mobappGetUserData(array('logFileName' => 'card_charge', 'formType' => $formType)); // get user data and validate
18334        $userArr = $userData['User'];
18335        $apiToken = $this->request->query['token'];
18336        $isFreeFlg  = false;
18337        $freeNumber = $monthlyFee = 0;
18338        $basicFee = 0;
18339        $lessonLimit = 0;
18340        $corporateIndiUser = false;
18341        $indiCorpTypeLight = false;
18342        $corporatePaymentAmount = 0;
18343
18344        // redirect to retry page if memcache does not exist or expired
18345        if (!$data = $this->memcache->get('mobappUserCreditChargeInfo_'.$apiToken)) {
18346            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.myTools::getMobappToken($_GET));
18347        }
18348
18349        // if corporate user and retain individual plan
18350        if (isset($userArr['corporate_id'])) {
18351            $corporateIndiUser = true;
18352            // get coporate individual plan data
18353            if ($corporateChargeMemData = $this->memcache->get('mobappCreditChargeCorporateData_' . $userArr['id'])) {
18354                $fAmount = $corporateChargeMemData['fAmount'];
18355                $corporatePaymentAmount = $corporateChargeMemData['paymentAmount'];
18356                $isFreeFlg = isset($corporateChargeMemData['freeFlg']) ? $corporateChargeMemData['freeFlg'] : false;
18357                $freeNumber = isset($corporateChargeMemData['freeNumber']) ? $corporateChargeMemData['freeNumber'] : 0;
18358                $monthlyFee = isset($corporateChargeMemData['monthlyFee']) ? $corporateChargeMemData['monthlyFee'] : 0;
18359                $lessonLimit = isset($corporateChargeMemData['lessonLimit']) ? $corporateChargeMemData['lessonLimit'] : 0;
18360            }
18361
18362            if ($data['ZPaymentFullLogs']['indiCorpType'] == Configure::read('corporate_type.light')) {
18363                $indiCorpTypeLight = true;
18364            }
18365        } else {
18366            $fAmount = myTools::formatAmount($data['ZPaymentFullLogs']['money']);
18367        }
18368
18369        $readSkipConfirmation = true;// forcec skip to post
18370
18371
18372        if ($this->request->is('post') || $readSkipConfirmation) {
18373            // - set flag, on submission set 10 seconds delay / cooldown
18374            $this->memcache->set(array(
18375                'key' => 'creditChargePaymentSucess'.$userArr['id'],
18376                'value' => true,
18377                'expire' => 10
18378            ));
18379
18380            // check if token matches token in session
18381            $checkToken = $this->checkTokenMobapp($apiToken, $data['cardToken'], 'card-charge-');
18382
18383            // check if token is true
18384            if ($checkToken) {
18385
18386                // unset previously set tokens
18387                $this->unsetTokenMobapp($apiToken, 'card-charge-');
18388
18389                $formType = isset($data['ZPaymentFullLogs']['formType']) ? $data['ZPaymentFullLogs']['formType'] : $formType;
18390
18391                $isLitePlanUser = (isset($data['ZPaymentFullLogs']['payment_plan_type']) && (int) $data['ZPaymentFullLogs']['payment_plan_type'] == 1  ) ? true : false;
18392
18393                $isChocottoPlanUser = (
18394                    isset($data['ZPaymentFullLogs']['payment_plan_type']) &&
18395                    (int) $data['ZPaymentFullLogs']['payment_plan_type'] == Configure::read('register_plan_types.chocotto')
18396                );        
18397
18398                // if corporate credit charge
18399                if (
18400                    $formType != Configure::read('payment_credit_force_charge') && 
18401                    !$isLitePlanUser &&
18402                    !$isChocottoPlanUser
18403                ) {
18404                    $data['ZPaymentFullLogs']['money'] = $corporatePaymentAmount;
18405                }
18406
18407                if($corporateIndiUser) {
18408                    $data['ZPaymentFullLogs']['paymentHash'] = $this->memcache->get('indiCorpPaymentHash_'.$userArr['id']);
18409                }
18410
18411                $totalReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userArr['id']) + $this->PaymentReceivable->computeReceivableReservationPayment($userArr['id'], false, Configure::read('appreciation_data.payment_element_type')) + $this->PaymentReceivable->computeReceivableReservationPayment($userArr['id'], false, Configure::read('payment_element_type.live'));
18412
18413                $data['ZPaymentFullLogs']['money'] += $totalReceivable;
18414
18415                if (isset($data['discountOption'])) {
18416                    $data['ZPaymentFullLogs']['money'] -= $data['discountOption']['amount'];
18417                }
18418                $this->Session->write('mobapp_show_welcome_back_modal',true);
18419
18420                //process zeus card
18421                $this->zeus_card_process_mobapp(array(
18422                    'data' => $data,
18423                    'form_type' => $formType,
18424                    'referrer' => array('controller' => 'Payment', 'action' => 'mobapp_credit_charge', '?' => array('token' => $apiToken)),
18425                    'api_token' => $apiToken
18426                ));
18427
18428            } else {
18429                return $this->redirect(myTools::getUrl() . '/mobapp/payment/failure_settlement'.myTools::getMobappToken($_GET));
18430            }
18431        }
18432
18433        if (isset($data['ZPaymentFullLogs']['cardnumber']) && !empty($data['ZPaymentFullLogs']['cardnumber'])) {
18434            $cardNumberArr = str_split($data['ZPaymentFullLogs']['cardnumber'], 4);
18435            $this->set('cardNumber', end($cardNumberArr));
18436        } else {
18437            $this->getAndSetCardInfo($userData['User']);
18438        }
18439
18440        $this->set('corporateIndiUser', $corporateIndiUser);
18441        $this->set('corporateType', myTools::getCoporateTypeUsingPaymentPlanId($userArr['payment_plan_id']));
18442        $this->set('indiCorpTypeLight', $indiCorpTypeLight);
18443        $this->set('fAmount', $fAmount);
18444        $this->set('data', $data);
18445        $this->set('apiToken', $apiToken);
18446        $this->set('lessonLimit', $lessonLimit);
18447        $this->set('isFreeFlg', $isFreeFlg);
18448        $this->set('freeNumber', $freeNumber);
18449        $this->set('monthlyFee', $monthlyFee);
18450        $this->set('monthlyPriceSymbol', myTools::getCurrencySymbol($userArr['currency_code']));
18451        $this->render(myTools::getDeviceUrl() . 'Payment/credit_charge_confirm');
18452    }
18453    /**
18454     * @api {get} /mobapp/payment/paypal_payment_credit_charge_confirm/:token mobapp_paypal_credit_charge_confirm()
18455     * @apiName mobapp_paypal_credit_charge_confirm
18456     * @apiGroup Payment
18457     * @apiDescription This endpoint is used to confirm the charging of the user's credit card using PayPal.
18458     * 
18459     * @apiParam {String} token User's token
18460     * 
18461     * @apiSuccess {View} Render Displays the paypal credit charge confirm page.
18462     * 
18463     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if credit charge data does not exist / expired / no token.
18464     * 
18465     * @apiSuccessExample Success Response:
18466     * Render Displays the paypal credit charge confirm page.
18467     * 
18468     * @apiErrorExample Error Response:
18469     * Redirects to {{ENV}}/mobapp/retrypage
18470     * 
18471     * @apiSampleRequest off
18472     */
18473    public function mobapp_paypal_credit_charge_confirm() {
18474        $this->layout = 'mobapp';
18475        $logFileName = 'paypal_debug';
18476        $formType = Configure::read('payment_credit_force_charge');
18477
18478        // get user data and validate
18479        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType));
18480        $user = $userData['User'];
18481        $apiToken = $this->request->query['token'];
18482
18483        // redirect to retry page if data does not exist or expired
18484        if (!$data = $this->memcache->get('mobappPaypalPaymentCreditChargeData_' . $apiToken)) {
18485            $this->log(__METHOD__ . ' credit charge data does not exist or expired. user api token --> ' . json_encode($apiToken), $logFileName);
18486            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage' . myTools::getMobappToken($_GET));
18487        }
18488
18489        $this->set('paypalFlg', true); // use for modal loader
18490        $this->set('paypalUserData', $userData['User']);
18491        $this->set('fAmount', myTools::formatAmount($data['ZPaymentFullLogs']['money']));
18492        $this->set('monthlyPriceSymbol', myTools::getCurrencySymbol($user['currency_code']));
18493        $this->set('userApiToken', $apiToken);
18494
18495        // set payment gateway type
18496        $this->memcache->set(array(
18497            'key' => 'mobappCreditChargePaymentGatewayType_' . $apiToken,
18498            'value' => $data['payment_gateway_type'],
18499            'expire' => 3600 // 1 hour
18500        ));
18501
18502        $this->render(myTools::getDeviceUrl() . 'Payment/paypal_credit_charge_confirm');
18503    }
18504    /**
18505     * @api {get} /mobapp/payment/paypal_payment_credit_charge_process/:token/:payment_plan_type/:negativeTesting mobapp_paypal_credit_charge_process()
18506     * @apiName mobapp_paypal_credit_charge_process
18507     * @apiGroup Payment
18508     * @apiDescription This endpoint is used to process the charging of the user's credit card using PayPal.
18509     * 
18510     * @apiParam {String} token User's token
18511     * @apiParam {Number} payment_plan_type Payment plan type
18512     * @apiParam {Number} negativeTesting Indicates if negative testing is used on the transaction. 1 for true, 0 for false.
18513     * 
18514     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/close?token=$apiToken&type=premium_plan_paid&re_enrolled=1 if payment is successful.
18515     * 
18516     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if data does not exist or expired
18517     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/payment/credit_charge?token=$apiToken if light plan data does not exist
18518     * @apiError {View} Redirect Redirets to {{ENV}}/mobapp/retrypage if annual discount option does not exist or is not enabled
18519     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/payment/credit_charge?token=$apiToken if chocotto plan data does not exist
18520     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/payment/credit_charge?token=$apiToken if paypal payment is not successful
18521     * 
18522     * @apiSuccessExample Success Response:
18523     * Redirects to {{ENV}}/mobapp/close?token=$apiToken&type=premium_plan_paid&re_enrolled=1
18524     * 
18525     * @apiErrorExample Error Response Data does not exist or expired:
18526     * Redirects to {{ENV}}/mobapp/retrypage
18527     * 
18528     * @apiErrorExample Error Response Light plan data does not exist:
18529     * Redirects to {{ENV}}/mobapp/payment/credit_charge?token=$apiToken
18530     * 
18531     * @apiErrorExample Error Response Annual discount option does not exist or is not enabled:
18532     * Redirects to {{ENV}}/mobapp/retrypage
18533     * 
18534     * @apiErrorExample Error Response Chocotto plan data does not exist:
18535     * Redirects to {{ENV}}/mobapp/payment/credit_charge?token=$apiToken
18536     * 
18537     * @apiErrorExample Error Response Paypal payment is not successful:
18538     * Redirects to {{ENV}}/mobapp/payment/credit_charge?token=$apiToken
18539     *
18540     * @apiSampleRequest off
18541     */
18542    public function mobapp_paypal_credit_charge_process() {
18543        $this->autoRender = false;
18544        $this->layout = false;
18545
18546        $logFileName = 'paypal_debug';
18547        $formType = Configure::read('payment_credit_force_charge');
18548
18549        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType));
18550        $get = $this->request->query;
18551        $apiToken = $get['token'];
18552        $memKey = 'mobappPaypalPaymentCreditChargeData_' . $apiToken;
18553        $res = array('success' => false);
18554
18555        //- pass original payment plan
18556        $userObj = new UserTable($userData['User']);
18557        $userData['User']['original_status_index'] = $userObj->getMembershipTypeIndex();
18558
18559        // redirect to retry page if data does not exist or expired
18560        if (!$data = $this->memcache->get($memKey)) {
18561            $this->log(__METHOD__ . ' credit charge data does not exist or expired. user api token --> ' . json_encode($apiToken), $logFileName);
18562            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage' . myTools::getMobappToken($_GET));
18563        }
18564
18565        $paymentPlanType = isset($get['payment_plan_type']) ? $get['payment_plan_type'] : 0;
18566
18567        if ($paymentPlanType == Configure::read('register_plan_types.light')) {
18568            // fetch light plan description
18569            $litePlanData = $this->PaymentPlanPrice->getPaymentData(array(
18570                'currencyCode' => $userData['User']['currency_code'],
18571                'paymentPlanId' => Configure::read('payment_plans.light_plan'),
18572                'logFileName' => 'card_reregister'
18573            ));
18574
18575            if (!$litePlanData) {
18576                // set the memcache error
18577                $this->memcache->set(array(
18578                    'key' => 'card-error-'.$apiToken,
18579                    'value' => __("Error : 決済失敗"),
18580                    'expire' => 3600 // 1 hour
18581                ));
18582
18583                return $this->redirect('/mobapp/payment/credit_charge?token='.$apiToken);
18584            }
18585        
18586            $userData['User']['price_id'] = $litePlanData['priceId'];
18587            $userData['User']['payment_plan_id'] = $litePlanData['paymentPlanId'];
18588        
18589            // - update data 
18590            $data['paymentPlanData'] = $litePlanData;
18591            $data['formType'] =  myTools::getLitePlanUserFormType($litePlanData['paymentPlanId']);
18592
18593        } elseif ($paymentPlanType == Configure::read('register_plan_types.premium_with_annual_discount_option')) {
18594            $annualDiscountOptionData = $this->DiscountOptionsPrice->getPaymentData(['currencyCode' => $userData['User']['currency_code'], 'discountOptionId' => Configure::read('discount_option.annual.plan_id')]);
18595
18596            // redirect to credit page if annual discount option does not exist or is not enabled
18597            if (!$annualDiscountOptionData) {
18598                return $this->redirect(myTools::getUrl() . '/mobapp/retrypage' . myTools::getMobappToken($_GET));
18599            }
18600
18601            unset($annualDiscountOptionData['contract_start']);
18602            $annualDiscountOptionData += [
18603                'dosh_event' => Configure::read('discount_option.dosh_event.annual_discount'),
18604                'dosh_status' => Configure::read('discount_option.dosh_status.monthly_discount')
18605            ];
18606
18607            // update payment transaction (add annual discount option data)
18608            $this->PaymentTransaction->updatePaymentParams(array('paymentHash' => $data['ZPaymentFullLogs']['paymentHash'], 'updateData' => ['annualDiscountOption' => $annualDiscountOptionData]));
18609
18610            $data['discountOption'] = $annualDiscountOptionData;
18611
18612        //- NJ-27262 chocotto plan    
18613        } elseif ($paymentPlanType == Configure::read('register_plan_types.chocotto')) {
18614            // fetch chocotto plan description
18615            $chocottoPlanData = $this->PaymentPlanPrice->getPaymentData(array(
18616                'currencyCode' => $userData['User']['currency_code'],
18617                'paymentPlanId' => Configure::read('payment_plans.chocotto_plan'),
18618                'logFileName' => 'card_reregister'
18619            ));
18620
18621            if (!$chocottoPlanData) {
18622                // set the memcache error
18623                $this->memcache->set(array(
18624                    'key' => 'card-error-'.$apiToken,
18625                    'value' => __("Error : 決済失敗"),
18626                    'expire' => 3600 // 1 hour
18627                ));
18628
18629                return $this->redirect('/mobapp/payment/credit_charge?token='.$apiToken);
18630            }
18631        
18632            //- NJ-36141: reset daily lesson time if changed to chocotto plan
18633            $this->UsersDetail->chocottoCampUserDetails($userData['User']['id'], true);
18634            
18635            $userData['User']['price_id'] = $chocottoPlanData['priceId'];
18636            $userData['User']['payment_plan_id'] = $chocottoPlanData['paymentPlanId'];
18637        
18638            // - update data
18639            $data['paymentPlanData'] = $chocottoPlanData;
18640            $data['formType'] = Configure::read('payment_credit_chocotto_force_charge');
18641        }
18642
18643        // NJ-32737
18644        $couponData = $this->Session->read('apply_coupon_usage_data');
18645
18646        if (!empty($couponData['useCouponAmount'])) {
18647            $data['couponUseSettlement'] = $couponData;
18648        }
18649
18650        if ((isset($get['negativeTesting']) && $get['negativeTesting']) || !$this->processPayPalPayment($data, $userData['User'])) {
18651            // set the memcache error
18652            $this->memcache->set(array(
18653                'key' => 'card-error-'.$apiToken,
18654                'value' => __("Error : 決済失敗"),
18655                'expire' => 3600 // 1 hour
18656            ));
18657
18658            return $this->redirect('/mobapp/payment/credit_charge?token='.$apiToken);
18659        }
18660
18661        $memKey = 'mobappCreditChargePaymentGatewayType_' . $apiToken;
18662
18663        // delete memcache payment gateway type
18664        if ($this->memcache->get($memKey)) {
18665            $this->memcache->delete($memKey);
18666        }
18667
18668        $this->memcache->delete('mobappUserCreditChargeInfo_'.$apiToken);
18669        return $this->redirect(array('controller' => 'Mobapp', 'action' => 'close', '?' => array('token' => $apiToken, 'type' => 'premium_plan_paid','re_enrolled' => 1)));
18670    }
18671
18672    /**
18673    * [addTransaction add payment transaction for mobapp]
18674    * @param array - user data
18675    * @return array - result - transaction password
18676    */
18677    private function mobappSetUpTransaction($formType = null, $paymentData = array()) {
18678        $pt = array();
18679
18680        switch ($formType) {
18681            case Configure::read('payment_credit_retry'):
18682                $logFileName = 'card_retry';
18683                break;
18684            case Configure::read('payment_credit_authentication'):
18685                $logFileName = 'card_registration';
18686                break;
18687            case Configure::read('payment_credit_force_charge'):
18688                $logFileName = 'card_charge';
18689                break;
18690            case Configure::read('payment_credit_change'):
18691                $logFileName = 'card_change';
18692                break;
18693            default:
18694                $logFileName = 'debug';
18695        }
18696
18697        if (!$formType) {
18698            $this->log(__METHOD__ . ' form type does not exist. ' . json_encode($formType), $logFileName);
18699            return $pt;
18700        }
18701
18702        if (!isset($paymentData['payment_plan_id']) && !isset($paymentData['paymentPlanId'])) {
18703            $this->log(__METHOD__ . ' missing parameter payment plan id. ' . json_encode($paymentData), $logFileName);
18704            return $pt;
18705        }
18706
18707        if (!isset($paymentData['price_id']) && !isset($paymentData['priceId'])) {
18708            $this->log(__METHOD__ . ' missing parameter price id. ' . json_encode($paymentData), $logFileName);
18709            return $pt;
18710        }
18711
18712
18713
18714        // set payment transactions
18715        $pt = $this->PaymentTransaction->setPaymentTransaction(array(
18716            'user_id' => $user['id'],
18717            'payment_hash' => $user['hash16'],
18718            'course_id' => Configure::read("credit.course_id")
18719        ));
18720
18721        // check if payment transaction exists
18722        if ($pt) {
18723            $result = array(
18724                'password' => isset($pt['password'])? $pt['password'] : null
18725            );
18726        }
18727
18728        // return password
18729        return isset($pt['password'])? $result['password'] : null;
18730    }
18731
18732    /**
18733    * check token for mobapp
18734    * @param apiToken - users api token, cardToken - token created when selecting card, key - key used to retrieve memcache cardToken
18735    * @return boolean
18736    */
18737    private function checkTokenMobapp($apiToken = null, $cardToken = null, $key = null){
18738        $cacheToken = $this->memcache->get($key.$apiToken);
18739        return ($cacheToken === $cardToken);
18740    }
18741
18742    /**
18743    * unset previously set card tokens memcache for mobapp
18744    */
18745    private function unsetTokenMobapp($apiToken = null, $key = null) {
18746        $cardToken = $this->memcache->get($key.$apiToken);
18747        if ($cardToken) {
18748            $this->memcache->delete($key.$apiToken);
18749        }
18750        return;
18751    }
18752
18753    /**
18754    * get users data using api token
18755    * @param token string
18756    * @return array - user data
18757    */
18758    private function getUserData($token) {
18759        $this->User->recursive = -1;
18760        $userData = $this->User->useReplica()->find('first', array(
18761            'joins' => array(
18762                array(
18763                    'table' => 'payment_svc_prices',
18764                    'alias' => 'PaymentPlanPrice',
18765                )
18766            ),
18767            'conditions' => array('User.api_token' => $token)
18768        ));
18769        return $userData ? $userData : false;
18770    }
18771
18772    /**
18773    * process zeus card 
18774    */
18775    private function zeus_card_process_mobapp($params = array()){
18776        $this->autoRender = false;
18777        //data
18778        $data = isset($params['data']) ? $params['data'] : null;
18779        $formType = isset($params['form_type']) ? $params['form_type'] : null;
18780        $referrer = isset($params['referrer']) ? $params['referrer'] : null;
18781        $apiToken = isset($params['api_token']) ? $params['api_token'] : null;
18782        $cardToken = isset($params['card_token']) ? $params['card_token'] : null;
18783        $paymentHash = isset($params['paymentHash']) ? $params['paymentHash'] : null;
18784        $urlRedirect = isset($data['page_origin']) ? $data['page_origin'] : null;
18785        $fromUnliOption = isset($params['unli_option']) ? $params['unli_option'] : null;
18786        $isLitePlanUser = (isset($params['isLitePlanUser']) && !empty($params['isLitePlanUser']));
18787
18788        $this->User->recursive = -1;
18789        $this->User->openDBReplica();
18790        // $userData = $this->User->findByApiToken($apiToken);
18791        $userData = $this->User->find('first', array(
18792            'fields' => array(
18793                'User.id',
18794                'User.email',
18795                'User.complimentary_code',
18796                'User.currency_code',
18797                'User.corporate_type'
18798            ),
18799            'conditions' => array(
18800                'User.api_token' => $apiToken
18801            ),
18802            'recursive' => -1
18803        ));
18804        $this->User->closeDBReplica();
18805
18806        if (!$userData) {
18807            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.myTools::getMobappToken($_GET));
18808        }
18809        
18810        // user
18811        $user = new UserTable($userData['User']);
18812
18813        $modelname ="ZPaymentFullLogs";
18814        $this->set(compact("modelname"));
18815
18816        $checkReregisterSession = $this->Session->read('mobapp_show_welcome_back_modal');
18817        if ($checkReregisterSession) {
18818            $this->Session->delete('mobapp_show_welcome_back_modal');
18819        }
18820
18821        // - if maintenance and mobapp process redirect
18822        if (myTools::zeusMaintenancePeriod()) {
18823            return $this->redirect(myTools::getUrl() . '/mobapp/payment/failure_settlement'.myTools::getMobappToken($_GET));
18824        }
18825
18826        if ($data) {
18827            switch ($formType) {
18828                case Configure::read('payment_credit_retry'):
18829                case Configure::read('payment_credit_chocotto_retry'):
18830                    // NC-7029 coupon discount
18831                    if (isset($data[$modelname]['discounted_amount'])) {
18832                        if ($data[$modelname]['money'] <= $data[$modelname]['discounted_amount']) {
18833                            $data[$modelname]['discounted_amount'] = $data[$modelname]['money'];
18834                            $data[$modelname]['money'] = 0;
18835                        } else {
18836                            $data[$modelname]['money'] -= $data[$modelname]['discounted_amount'];
18837                        }
18838                    }
18839                case Configure::read('payment_credit_force_charge'):
18840                case Configure::read('payment_individual_corporate_standard'):
18841                case Configure::read('payment_individual_corporate_premium'):
18842                case Configure::read('payment_prepaid_corporate_light_member'):
18843                case Configure::read('payment_lite_credit_paid'):
18844                case Configure::read('payment_credit_chocotto_monthly_payment'):
18845                case Configure::read('payment_credit_chocotto_force_charge'):
18846                    $money = $data[$modelname]['money'];
18847                    break;
18848                case Configure::read('payment_credit_change'):
18849                case Configure::read('corporate_credit_card_registration'):
18850                    // get reserve payment receivable
18851                    $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($user->id);
18852
18853                    // get appreciation payment receivable
18854                    $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($user->id, false, Configure::read('appreciation_data.payment_element_type'));
18855
18856                    // get live lesson payment receivable
18857                    $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($user->id, false, Configure::read('payment_element_type.live'));
18858
18859                    $money = $receivablePayment + $appreciationReceivable + $liveLessonReceivable;
18860                    break;
18861                case Configure::read('payment_credit_authentication'):
18862                case Configure::read('payment_lite_credit_free'):
18863                case Configure::read('payment_credit_chocotto_free'):    
18864                    $money = 0;
18865                    break;
18866                default:
18867                    $money = 0;
18868                    $formType = Configure::read('payment_credit_default');
18869                    break;
18870            }
18871            
18872            $pData = array(
18873                'clientIp' => (int) $data[$modelname]['clientip'],
18874                'cardNumber' => isset($data[$modelname]['cardnumber']) ? (int) $data[$modelname]['cardnumber'] : '',
18875                'expyy' => isset($data[$modelname]['expyy']) ? (int) $data[$modelname]['expyy'] : 0,
18876                'expmm' => isset($data[$modelname]['expmm']) ? (int) $data[$modelname]['expmm'] : 0,
18877                'telNo' => (int) $data[$modelname]['telno'],
18878                'email' => $user->email,
18879                'username' => isset($data[$modelname]['username']) ? mb_strtoupper($data[$modelname]['username']) : '',
18880                'sendId' => $user->id,
18881                'money' => $money,
18882                'tokenKey' => isset($data[$modelname]['zeusTokenValue']) ? $data[$modelname]['zeusTokenValue'] : '',
18883                'paymentHash' => $data[$modelname]['paymentHash']
18884            );
18885
18886            // send curl request
18887            if (isset($data['zeus_card_option']) && $data['zeus_card_option'] == "prev") {
18888                $res = ZChargeComponent::charge_with_regsterd_card(json_encode($pData));
18889            } else {
18890
18891                // update payment params -  add card expiration date
18892                if (isset($data[$modelname]['expyy']) && isset($data[$modelname]['expmm'])) {
18893                    $paymentParamsData = array('cardExpirationDate' => date('Y-m-t', strtotime($data[$modelname]['expyy'] . '-' . $data[$modelname]['expmm'])));
18894                    $this->PaymentTransaction->updatePaymentParams(array('paymentHash' => $data[$modelname]['paymentHash'], 'updateData' => $paymentParamsData));
18895                }
18896
18897                // get zeus challenge flag
18898                $zeus3DSecureChallengeFlg = $this->memcache->get('zeus3DSecureChallengeFlg_' . $user->id);
18899                // NJ-25522: payment was charged after challenge already
18900                if ($zeus3DSecureChallengeFlg) {
18901                    $zeus3DSecurePaymentSuccessFlg = $this->memcache->get('zeus3DSecurePaymentSuccessFlg_' . $user->id);
18902                    $res = !empty($zeus3DSecurePaymentSuccessFlg) && $zeus3DSecurePaymentSuccessFlg == 'OK' ? 'Success_order' : 'failure_order';
18903                    // clear flag
18904                    $this->memcache->delete('zeus3DSecureChallengeFlg_' . $user->id);
18905                    $this->memcache->delete('zeus3DSecurePaymentSuccessFlg_' . $user->id);
18906
18907                // default process without challenge, charge directly
18908                } else {
18909                    $res = $this->ZCharge->charge_regist(json_encode($pData));
18910                }
18911            }
18912
18913            // if successful
18914            if ( $res[0] == "Success_order" || $res == "Success_order") {
18915                if ($formType == Configure::read('payment_credit_authentication')) {
18916                    // send registration completion email
18917                    App::uses('myMailer','Lib');
18918                    $mail_id = Configure::read('site_in_mail.student_registration_complete');
18919                    if ($userData &&  !in_array($userData['User']['currency_code'], Configure::read('global_free_trail_currencies') ) ) {
18920                        $mail_id = Configure::read('site_in_mail.registration_no_trial_currencies');
18921                    }
18922                    myMailer::sendTemplateMail($mail_id, $userData['User']['email'], $userData['User'], array(), 'User');
18923                    $this->Session->write('reenroll_native_option', true);
18924                    return $this->redirect(array('controller' => 'Payment', 'action' => 'mobapp_credit_register_notice_to_user', '?' => array('token' => $apiToken, 'cardToken' => $cardToken)));
18925                } else if (
18926                    $formType == Configure::read('payment_credit_force_charge') ||
18927                    $formType == Configure::read('payment_lite_credit_paid') ||
18928                    $formType == Configure::read('payment_credit_chocotto_monthly_payment') ||
18929                    $formType == Configure::read('payment_credit_chocotto_force_charge')
18930                ) {
18931
18932                    // - set flag
18933                    $this->memcache->set(array(
18934                        'key' => 'creditChargePaymentSucess'.$user->id,
18935                        'value' => true,
18936                        'expire' => 30 // 30 sec
18937                    ));
18938
18939                    $this->memcache->delete('mobappUserCreditChargeInfo_'.$apiToken);
18940                    $_addParams = array(
18941                        'token' => $apiToken
18942                    );
18943                    if ($checkReregisterSession) {
18944                        $_addParams = array(
18945                            'token' => $apiToken,
18946                            're_enrolled' => 1
18947                        );
18948                    }
18949
18950                    if ($formType == Configure::read('payment_lite_credit_paid')) {
18951                        $this->liteUserAddCoinRewardForReenroll(array('id' => $user->id));
18952                    }
18953
18954                    if (isset($user->complimentary_code) && $this->memcache->get('com_plan_user_' . $user->id)) {
18955                        $this->memcache->delete('com_plan_user_' . $user->id);
18956                        $_addParams['type'] = 'special_complimentary_plan';
18957                        return $this->redirect(array('controller' => 'Mobapp', 'action' => 'close', '?' => $_addParams));
18958                    } else {
18959                        $_addParams['type'] = 'premium_plan_paid';
18960                        $_addParams['re_enrolled'] = 1;
18961                        return $this->redirect(array('controller' => 'Mobapp', 'action' => 'close', '?' => $_addParams));
18962                    }
18963                } else if ($formType == Configure::read('payment_credit_change')) {
18964                    if ($urlRedirect) {
18965                        $urlParams = "?token=".$apiToken;
18966                        if ( $urlRedirect == 2 ) { // ebook
18967                            $urlParams = $urlParams."&new_card=ebook";
18968                        }
18969                        return $this->redirect(myTools::getUrl() . '/mobapp/store/card_register_complete' . $urlParams );
18970                    } else {
18971                        $_addParams = array(
18972                            'token' => $apiToken,
18973                            'type' => 'card_change'
18974                        );
18975
18976                        if (isset($fromUnliOption) && !empty($fromUnliOption) && $fromUnliOption==1){
18977                            return $this->redirect(myTools::getUrl() . '/mobapp/option/native-start' . '?token='.$apiToken . '&unli_option='.$fromUnliOption);
18978                        } else {
18979                            return $this->redirect(array('controller' => 'Mobapp', 'action' => 'close', '?' => $_addParams));
18980                        }
18981                    }
18982                } else if ($formType == Configure::read('payment_credit_retry')) {
18983                    // - flag manual paying user sucess
18984                    UserTable::saveManualPayingUsersToMemcache($user->id);
18985                    $this->memcache->delete('mobappUserCreditRetryInfo_'.$apiToken);
18986                        $_addParams = array(
18987                            'token' => $apiToken,
18988                            'type' => 'credit_retry_complete'
18989                        );
18990                        if ($checkReregisterSession) {
18991                            $_addParams['re_enrolled'] = 1;
18992                        }
18993
18994                    return $this->redirect(array('controller' => 'Payment', 'action' => 'mobapp_credit_retry_complete', '?' => $_addParams));
18995                } else if (
18996                    $formType == Configure::read('payment_individual_corporate_standard') ||
18997                    $formType == Configure::read('payment_individual_corporate_premium') ||
18998                    $formType == Configure::read('payment_prepaid_corporate_light_member')
18999                ) {
19000                    if ($this->memcache->get('mobappCreditChargeCorporateData_' . $user->id)) {
19001                        $this->memcache->delete('mobappCreditChargeCorporateData_' . $user->id);
19002                    }
19003
19004                    $_addParams = array(
19005                        'token' => $apiToken,
19006                    );
19007
19008                    if ($checkReregisterSession) {
19009                        $_addParams['re_enrolled'] = 1;
19010                    }
19011
19012
19013                    // Credit charge
19014                    if ( $this->memcache->get('mobappUserCreditChargeInfo_'.$apiToken) ) {
19015                        $_addParams['type'] = 'corporate_light_plan';
19016                        $this->memcache->delete('mobappUserCreditChargeInfo_'.$apiToken);
19017                    }
19018                    // Credit retry
19019                    if ( $this->memcache->get('mobappUserCreditRetryInfo_'.$apiToken) ) {
19020                        // - flag manual paying user sucess
19021                        UserTable::saveManualPayingUsersToMemcache($user->id);
19022                        $this->memcache->delete('mobappUserCreditRetryInfo_'.$apiToken);
19023                        $_addParams['type'] = 'credit_retry_complete';
19024                        
19025                    }
19026
19027                    // NJ-33414 Update User's Lesson Request to Default
19028                    $this->UsersDetail->openDBReplica();
19029                    $usersDetail = $this->UsersDetail->find('first', array(
19030                        'fields' => array('lesson_request_flg'),
19031                        'conditions' => array('UsersDetail.user_id' => $userData['User']['id']),
19032                        'recursive' => -1
19033                    ));
19034                    $this->UsersDetail->closeDBReplica();
19035
19036                    if( $usersDetail ) {
19037                        $this->UsersDetail->clear();
19038                        $this->UsersDetail->query("
19039                                UPDATE
19040                                    `users_detail`
19041                                SET
19042                                    `lesson_request_flg` = 1
19043                                WHERE
19044                                    `user_id` = {$userData['User']['id']}
19045                        ");
19046                    } else {
19047                        $this->UsersDetail->clear();
19048                        $this->UsersDetail->set([
19049                            'user_id' => $userData['User']['id'],
19050                            'individual_card_fail_flg'    => 0,
19051                            'lesson_request_flg' => 1
19052                        ]);
19053                        $this->UsersDetail->validate = [];
19054                        $this->UsersDetail->save();
19055                    }
19056                    
19057                    if ($this->memcache->get('mobappcorporateIndiPrices_' . $apiToken)) {
19058                        $this->memcache->delete('mobappCcorporateIndiPrices_' . $apiToken);
19059                    }
19060                                        
19061                    return $this->redirect(array('controller' => 'Mobapp', 'action' => 'close', '?' => $_addParams));
19062                } else {
19063                    return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.myTools::getMobappToken($_GET));
19064                }
19065            } else {
19066                // handle errors
19067                $this->handleCreditResponseErrorMobapp(array(
19068                    'res' => $res, 
19069                    'referrer' => $referrer,
19070                    'api_token' => $apiToken
19071                ));
19072            }
19073        }
19074    }
19075
19076    // catch errors for mobapp
19077    private function handleCreditResponseErrorMobapp($params = array()){
19078        //data
19079        $res = isset($params['res']) ? $params['res'] : null;
19080        $referrer = isset($params['referrer']) ? $params['referrer'] : null;
19081        $apiToken = isset($params['api_token']) ? $params['api_token'] : null;
19082
19083        // errors
19084        $error = "";
19085        $failureOrder = "failure_order";
19086        $maintenance = "maintenance";
19087        $connectError = "connect error";
19088        $cardNumberError = "Invalid Cardnumber";
19089        $telnoError = "Invalid telno";
19090        $usernameError = "Invalid username";
19091        $invalidClientIp = "Invalid clientip";
19092
19093        // check error message
19094        if ($res[0] == $failureOrder || $res == $failureOrder) {
19095            $error = __("Error : 決済失敗");
19096        } else if ($res[0] == $maintenance || $res == $maintenance) {
19097            $error = __("Error : メンテナンス中");
19098        } else if ($res[0] == $connectError || $res == $connectError) {
19099            $error = __("Error : Connect Error");
19100        } else if ($res[0] == $cardNumberError || $res == $cardNumberError) {
19101            $error = __("Error : カード番号が正しくありません 半角数字で入力してください。ハイフン(-)は必要ありません。");
19102        } else if ($res[0] == $telnoError || $res == $telnoError) {
19103            $error = __("Error : 電話番号が正しくありません 半角数字で入力してください。ハイフン(-)は必要ありません。");
19104        } else if ($res[0] == $usernameError || $res == $usernameError) {
19105            $error = __("Error : クレジットカードに記載されている名前を半角英字で入力してください。");
19106        } else if ($res[0] == $invalidClientIp || $res == $invalidClientIp) {
19107            $error = __("Error : 決済失敗");
19108        } else {
19109            $error = $res;
19110        }
19111
19112        // set the memcache error
19113        $this->memcache->set(array(
19114            'key' => 'card-error-'.$apiToken,
19115            'value' => $error,
19116            'expire' => 3600
19117        ));
19118
19119        //redirect to credit card select
19120        return $this->redirect($referrer);
19121    }
19122    /**
19123     * @api {get} /:language/payment/failure_family failure_family()
19124     * @apiName failure_family
19125     * @apiGroup Payment
19126     * @apiDescription This endpoint is used to display failure family page.
19127     * 
19128     * @apiParam {String} language Language code (ja/en).
19129     * 
19130     * @apiSuccess {View} Render Renders the failure family page.
19131     * @apiSuccess {View} Render Renders the failure family page sp version for mobile
19132     * 
19133     * @apiSuccessExample Success Response PC:
19134     * Renders the failure family page.
19135     * 
19136     * @apiSuccessExample Success Response Mobile:
19137     * Renders the failure family page sp version for mobile.
19138     * 
19139     * @apiSampleRequest off
19140     */
19141    public function failure_family() {
19142        if ($this->RequestHandler->isMobile()) {
19143            $this->sp_failure_family();
19144        }
19145    }
19146    
19147    public function sp_failure_family(){
19148        $this->layout = "mobile";
19149        $this->render('/Mobile/Payment/failure_family');
19150    }
19151
19152    /**
19153     * Get user id from zeuspay kickback data
19154     * @param array $data
19155     * @return int $userId
19156    */
19157    private function getUserId($data = null) {
19158        $userId = 0;
19159        if ($data) {
19160            // check if sendpoint and sendid are exist
19161            if (isset($data['sendpoint']) && $data['sendpoint'] && isset($data['sendid']) && $data['sendid']) {
19162                $sendPoint = $this->decodeSendPointData($data['sendpoint']);
19163                // family plan user
19164                $formTypes = array(
19165                    Configure::read('payment_credit_family_monthly_payment'),
19166                    Configure::read('payment_credit_coin_purchase'),
19167                    Configure::read('payment_credit_textbook_purchase'),
19168                    Configure::read('payment_credit_fund'),
19169                    Configure::read('payment_credit_receivable')
19170                );
19171                if (
19172                    isset($sendPoint['formType']) && in_array($sendPoint['formType'], $formTypes) 
19173                    && isset($sendPoint['familyId']) && $sendPoint['familyId']
19174                ) {
19175                    $userId = $sendPoint['familyId'];
19176                } else {
19177                    $userId = $data['sendid'];
19178                }
19179            }
19180        }
19181        return $userId;
19182    }
19183
19184    /**
19185    * decode sendPoint data from kickback
19186    * @return array
19187    */
19188    private function decodeSendPointData($args = null) {
19189        $this->log(__METHOD__ . json_encode($args), 'debug');
19190        $sendPointKeyEquiv = array(
19191            'r' => 'remoteAddress',
19192            'p' => 'paymentType',
19193            'm' => 'formType',
19194            'w' => 'password',
19195            'f' => 'familyId',
19196            't' => 'platform',
19197            'd' => 'cronDateRun' // hotfix_NC-3152
19198        );
19199
19200        $arrData = array();
19201        $data = '';
19202        if ($args) {
19203            $break = explode('|', $args);
19204            for ($i=0; $i<count($break); $i++) {
19205                unset($data);
19206                $data = explode(':', $break[$i]);
19207                if ($data) {
19208                    $index = $sendPointKeyEquiv[$data[0]];
19209                    $arrData[$index] = isset($data[1]) ? $data[1] : '';
19210                }
19211            }
19212        }
19213        return $arrData;
19214    }
19215    /**
19216     * @api {get} /mobapp/payment/failure_family/:token failureFamily()
19217     * @apiName failureFamily
19218     * @apiGroup Payment
19219     * @apiDescription This endpoint is used to display failure family page.
19220     * 
19221     * @apiParam {String} token User's api token.
19222     * 
19223     * @apiSuccess {View} Render Renders the failure family page.
19224     * 
19225     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if token / user does not exist.
19226     * 
19227     * @apiSuccessExample Success Response:
19228     * Renders the failure family page.
19229     * 
19230     * @apiErrorExample Error Response:
19231     * Redirects to {{ENV}}/mobapp/retrypage if token / user does not exist.
19232     * 
19233     * @apiSampleRequest off
19234     */
19235    public function failureFamily() {
19236        $this->layout = "mobapp";
19237        // get $_GET url paramters
19238        $getParams = $this->params->query;
19239
19240        if (empty($getParams['token'])) {
19241            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.myTools::getMobappToken($_GET));
19242        }
19243
19244        $data =  $this->User->find('count',array(
19245            'conditions' => array('User.api_token' => $getParams['token']),
19246            'recursive' => -1
19247        ));
19248
19249        if (!$data) {
19250            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.myTools::getMobappToken($_GET));
19251        }
19252        $this->set('token', $getParams['token']);
19253        $this->set('title_for_layout', '退会手続き');
19254        $this->render(myTools::getDeviceUrl() . 'Payment/failure_family');
19255    }
19256
19257    /**
19258     * NC-3914: get user card number and card logo and use it in view.
19259     * @param array $userData
19260     */
19261    private function getAndSetCardInfo($userData = array()) {
19262        $cardInfo = '';
19263        if ($userData) {
19264            $cardNumber = $userData['card_number'];
19265            $cardBrand = $userData['card_brand'];
19266            if (
19267                (is_null($cardNumber) || is_null($cardBrand)) &&
19268                !isset($userData['corporate_id']) && !isset($userData['payment_plan_id'])
19269            ) {
19270                // get user last successful payment card info.
19271                $cardInfo = $this->Payment->getUserCardInfo($userData['id']);
19272                $cardNumber = isset($cardInfo['cardNumber']) ? $cardInfo['cardNumber'] : null;
19273                $cardBrand = isset($cardInfo['cardBrand']) ? $cardInfo['cardBrand'] : null;
19274            }
19275        }
19276
19277        // get card logo
19278        $cardLogos = array(
19279            'A' => 'logo_americanexpress.png',
19280            'D' => 'logo_dinersclub.png',
19281            'J' => 'logo_jcb.png',
19282            'M' => 'logo_mastercard.png',
19283            'V' => 'Icon_visa.png',
19284            'P' => 'Icon_paypal.png',
19285            'TEST' => 'Icon_visa.png'
19286        );
19287
19288        $cardBrands = array(
19289            'A' => 'AMERICAN EXPRESS',
19290            'D' => 'DINERS CLUB',
19291            'J' => 'JCB',
19292            'M' => 'MASTERCARD',
19293            'V' => 'VISA',
19294            'P' => 'PAYPAL',
19295            'TEST' => 'VISA'
19296        );
19297
19298        $this->set('cardNumber', isset($cardNumber) && !empty($cardNumber) ? $cardNumber : null);
19299        $this->set('cardLogo', isset($cardLogos[$cardBrand]) ? $cardLogos[$cardBrand] : null);
19300        $this->set('cardBrand', isset($cardBrands[$cardBrand]) ? $cardBrands[$cardBrand] : null);
19301    }
19302
19303    /**
19304     * NC-3914: check if user_new_card_info session exist
19305     * if exist then set view vars
19306     * delete session
19307     */
19308    private function setPaymentViewVars() {
19309        $userCardInfo = $this->Session->read('user_new_card_info');
19310        if ($userCardInfo) {
19311            $this->set('data', $userCardInfo);
19312            $this->Session->delete('user_new_card_info');
19313        }
19314    }
19315    /**
19316     * @api {get} /:language/payment/failure_settlement failure_settlement()
19317     * @apiName failure_settlement
19318     * @apiGroup Payment
19319     * @apiDescription This endpoint is used to display failure settlement page.
19320     * 
19321     * @apiParam {String} language Language code.
19322     * 
19323     * @apiSuccess {View} Render Renders the failure settlement page.
19324     * @apiSuccess {View} Render Renders the failure settlement sp page
19325     * 
19326     * @apiSuccessExample Success Response PC:
19327     * Renders the failure settlement page.
19328     * 
19329     * @apiSuccessExample Success Response Mobile:
19330     * Renders the failure settlement sp page.
19331     * 
19332     * @apiSampleRequest off
19333     */
19334    public function failure_settlement(){
19335        if ($this->RequestHandler->isMobile()) {
19336            $this->sp_failure_settlement();
19337        }
19338    }
19339    /**
19340     * @api {get} /mobapp/payment_failure_settlement/:token/:referer mobapp_failure_settlement()
19341     * @apiName mobapp_failure_settlement
19342     * @apiGroup Payment
19343     * @apiDescription This endpoint is used to display failure settlement page.
19344     * 
19345     * @apiParam {String} token User's api token.
19346     * @apiParam {String} referer Referer url.
19347     * 
19348     * @apiSuccess {View} Render Renders the failure settlement page.
19349     * 
19350     * @apiSuccessExample Success Response:
19351     * Renders the failure settlement page.
19352     * 
19353     * @apiSampleRequest off
19354     */
19355    public function mobapp_failure_settlement(){
19356        $token = !empty($this->request->query['token']) ? $this->request->query['token'] : "";
19357        $type = !empty($this->request->query['type']) ? $this->request->query['type'] : "";
19358        $fromPage = !empty($this->request->query['from_page']) ? $this->request->query['from_page'] : "";
19359        $unliOption = !empty($this->request->query['unli_option']) ? $this->request->query['unli_option'] : "";
19360        $referer = !empty($this->request->query['referer']) ? $this->request->query['referer'] : myTools::getUrl() . "/mobapp/payment/credit_change?token=" . $token;
19361
19362        $this->set('fromPage', $fromPage);
19363        $this->set('unliOption', $unliOption);
19364        $this->set('token', $token);
19365        $this->set('type', $type);
19366        $this->set('referer', $referer);
19367        $this->layout = "mobapp";
19368        $this->render(myTools::getDeviceUrl() . 'Payment/failure_settlement');
19369    }
19370    
19371    public function sp_failure_settlement(){
19372        $type = !empty($this->request->query['type']) ? $this->request->query['type'] : "";
19373        $fromPage = !empty($this->request->query['from_page']) ? $this->request->query['from_page'] : "";
19374        $unliOption = !empty($this->request->query['unli_option']) ? $this->request->query['unli_option'] : "";
19375        
19376        $this->set('type', $type);
19377        $this->set('fromPage', $fromPage);
19378        $this->set('unliOption', $unliOption);
19379        $this->layout = "mobile";
19380        $this->render('/Mobile/Payment/failure_settlement');
19381    }
19382
19383    /**
19384    * NC-4770:  Worldpay get users data using api token
19385    * @param string $token
19386    * @return array $data
19387    */
19388    private function getWPUserData($token) {
19389        $data = $this->User->useReplica->find('first', array(
19390            'fields' => array(
19391                'User.id',
19392                'User.email',
19393                'SettlementCurrency.currency'
19394            ),
19395            'joins' => array(
19396                array(
19397                    'table' => 'settlement_currency',
19398                    'alias' => 'SettlementCurrency',
19399                    'type' => 'LEFT',
19400                    'conditions' => 'SettlementCurrency.id = User.settlement_currency_id'
19401                )
19402            ),
19403            'conditions' => array('User.api_token' => $token),
19404            'recursive' => -1
19405        ));
19406
19407        return $data ? $data : array();
19408    }
19409
19410    /**
19411     * NC-4770: Worldpay common method for updating user's payment transaction
19412     * @param array $params
19413     * @return array $result
19414     */
19415    public function updatePaymentTransaction($params = array()) {
19416        $logFileName = isset($params['logFileName']) ? $params['logFileName'] : 'debug';
19417        $result = array();
19418        if (
19419            !empty($params['id']) && isset($params['fields']) && !empty($params['logFileName'])
19420        ) {
19421            $updateData = array(
19422                'id' => $params['id'],
19423                'fields' => $params['fields']
19424            );
19425
19426            $result = $this->PaymentTransaction->updateWPPaymentTransaction($updateData);
19427        }
19428
19429        if (!$result) {
19430            $this->log(__METHOD__ .' Failed to update payment transaction. update data --> ' . json_encode($params), $logFileName);
19431        }
19432
19433        return $result;
19434    }
19435
19436    public function getHostedPage() {
19437        $this->layout = '';
19438        $logFileName = isset($this->request->data['logFileName']) ? $this->request->data['logFileName'] : 'debug';
19439
19440        $postData = $this->request->data;
19441        if ($this->request->is('post')) {
19442
19443            // throw exception if there is/are missing parameter(s)
19444            if (
19445                !isset($postData['logFileName']) ||
19446                !isset($postData['apiToken']) ||
19447                !isset($postData['formType']) ||
19448                !isset($postData['successUrl']) ||
19449                !isset($postData['paymentMethodType']) ||
19450                !isset($postData['memKeyError']) ||
19451                !isset($postData['referrer']) ||
19452                (
19453                    empty(trim($postData['apiToken'])) &&
19454                    $postData['apiToken'] !== 0 &&
19455                    $postData['apiToken'] !== '0'
19456                )
19457            ) {
19458                $this->log(__METHOD__ . ' Missing parameters. post data --> ' . json_encode($postData), $logFileName);
19459                throw new BadRequestException("Missing parameter(s).");
19460            }
19461
19462            // set variables
19463            $apiToken = $postData['apiToken'];
19464            $formType = $postData['formType'];
19465            $successUrl = urldecode($postData['successUrl']);
19466            $paymentMethodType = $postData['paymentMethodType'];
19467
19468            // get payment method (debit or credit)
19469            $paymentMethod = explode('_', $paymentMethodType);
19470            $paymentMethod = isset($paymentMethod[0]) ? $paymentMethod[0] : 'debit';
19471
19472            $nominalAmountArr = myTools::getWorldpayNominalAmountList($paymentMethod, myTools::getWPMerchantCode($paymentMethodType));
19473            $memKeyError = $postData['memKeyError'];
19474            $referrer = $postData['referrer'];
19475            $status = 0; // default pending
19476
19477            $userParams = array(
19478                'fields' => array(
19479                    'User.id',
19480                    'User.email',
19481                    'User.nickname',
19482                    'User.card_token',
19483                    'User.charge_flg',
19484                    'User.fail_flg',
19485                    'User.currency_code',
19486                    'User.payment_plan_id',
19487                    'User.price_id',
19488                    'User.double_check_flg',
19489                    'User.status',
19490                    'User.complimentary_code',
19491                    'User.card_company',
19492                    'User.first_charge_date',
19493                    'PaymentPlanPrice.amount'
19494            ),
19495                'apiToken' => $apiToken
19496            );
19497
19498            // throw exception if api token not exist
19499            if (!$userData = $this->User->getWPMobappUserData($userParams)) {
19500                $this->log(__METHOD__ . ' User api token does not exist. User params --> ' . json_encode($userParams), $logFileName);
19501                throw new InternalErrorException("User api token does not exist.");
19502            }
19503
19504            $userId = $userData['User']['id'] ?? null;
19505            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - POST DATA --> ' . json_encode($postData), 'error');
19506
19507            $userCurrencyCode = $userData['User']['currency_code'];
19508            $complimentaryCode = $userData['User']['complimentary_code'];
19509
19510            // NC-9168: override currency if worldpay card auth and JPY currency
19511            $expectedUserCurrency = $this->allowedCurrencies[$this->localizeDir];
19512            if (isset($postData['ncTerminalType']) && $postData['ncTerminalType'] == 1 &&
19513                $formType == Configure::read('payment_credit_authentication') && $userData['User']['currency_code'] != $expectedUserCurrency) {
19514                // Get localized language equivalent currency code
19515                if (
19516                    isset($this->localizeDir) && 
19517                    in_array($this->localizeDir, array_keys($this->allowedCurrencies)) &&
19518                    // do not update currency_code if user account has complimentary code
19519                    empty($complimentaryCode)
19520                ) {
19521                    $userCurrencyCode = ($this->localizeDir == 'zh-cn') ? 'USD' : $this->allowedCurrencies[$this->localizeDir];
19522                    // NC-9629: do not override if JPY
19523                    if ($userCurrencyCode == Configure::read('default.user_currency')) {
19524                        $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - [NC-9629] do not override currency with ' . $userCurrencyCode . ' - ' . json_encode($userData), 'error');
19525                    } else {
19526                        $this->User->validate = array();
19527                        $this->User->read(array('currency_code'), $userData['User']['id']);
19528                        $this->User->set(array('currency_code' => $userCurrencyCode));
19529                        $this->User->save();
19530                        $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - [NC-9168] override currency with ' . $userCurrencyCode . ' - ' . json_encode($userData), 'error');
19531                    }
19532                }
19533            }
19534
19535            // set variables
19536            $paymentPlanPriceAmount = $userData['PaymentPlanPrice']['amount'];
19537            $userData = $userData['User'];
19538            $currencyCode = $userCurrencyCode;
19539            $paymentPlanId = $userData['payment_plan_id'];
19540            $priceId = $userData['price_id'];
19541            $orderCode = myTools::generateOrderCode($userId);
19542            $wpPaymentAmount = $nominalAmountArr[$currencyCode];
19543            $ncPaymentAmount = 0;
19544
19545            switch ($formType) {
19546                case Configure::read('payment_credit_authentication'):
19547                    $tokenReason = 'Payment Credit Registration';
19548                    if (!isset($priceId)) {
19549                        // get payment data
19550                        $paymentData = $this->PaymentPlanPrice->getPaymentData(array(
19551                            'currencyCode' => $currencyCode,
19552                            'paymentPlanId' => Configure::read('payment_plans.free_trial'),
19553                            'logFileName' => $logFileName
19554                        ));
19555
19556                        // throw error exception if does not exist
19557                        if (!$paymentData) {
19558                            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Payment plan does not exist. - payment_credit_authentication', 'error');
19559                            throw new InternalErrorException("Payment plan does not exist.");
19560                        }
19561
19562                        $priceId = $paymentData['priceId'];
19563                    }
19564                    $paymentPlanId = Configure::read('payment_plans.free_trial');
19565
19566                    // Check if membership type is already Premium Plan(Free)
19567                    if (isset($postData['userRegister']) && $postData['userRegister'] == 1 && $this->memcache->get('wp_register_completed_'.$userId)) {
19568                        $this->Auth->login($userData);
19569                        $this->Session->write('redirect-to-notice-to-user', true);
19570                        $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - already_enrolled_free_trial', 'error');
19571                        throw new InternalErrorException('already_enrolled_free_trial');
19572                    }
19573                    break;
19574                case Configure::read('payment_credit_change'):
19575                    if (!isset($priceId) || !isset($paymentPlanId)) {
19576                        $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Price id or payment plan id is/are empty.', 'error');
19577                        throw new InternalErrorException("Price id or payment plan id is/are empty.");
19578                    }
19579
19580                    // add reserve payment amount
19581                    $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userId);
19582
19583                    // add appreciation lesson amount
19584                    $receivablePayment += $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.appreciation'));
19585
19586                    // add live lesson amount
19587                    $receivablePayment += $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.live'));
19588
19589                    // change payment method type to payment, if has receivable payment
19590                    if ($receivablePayment > 0) {
19591                        $paymentMethodType = $paymentMethod . '_payment';
19592                        $wpPaymentAmount = $ncPaymentAmount = $receivablePayment;
19593                    }
19594
19595                    $tokenReason = 'Payment Credit Change';
19596                    break;
19597                case Configure::read('payment_credit_retry'):
19598                    // get payment data
19599                    if (!$paymentData = $this->getRetryPaymentData($userData, $logFileName)) {
19600                        $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Payment plan does not exist. - payment_credit_retry', 'error');
19601                        throw new InternalErrorException("Payment plan does not exist.");
19602                    }
19603
19604                    $wpPaymentAmount = $paymentData['amount'];
19605                    $priceId = $paymentData['priceId'];
19606                    $paymentPlanId = $paymentData['paymentPlanId'];
19607                    
19608                    // NJ-47740 - get monthly reqeust coupon discount
19609                    $coupon = $this->UsersCouponV1->getCouponUseRequest(array(
19610                        'userId' => $userId,
19611                        'kbn' => Configure::read('coupon_kbn.monthly_settlement')
19612                    ));
19613                    
19614                    if (!empty($coupon['amount']) && !empty($coupon['grp_id'])) {
19615                        
19616                        if ($coupon['amount'] >= $wpPaymentAmount) {
19617                            $userData['monthlyDiscount'] = $wpPaymentAmount;
19618                            $wpPaymentAmount = 0;
19619                        } else {
19620                            $wpPaymentAmount -= $userData['monthlyDiscount'] = $coupon['amount'];
19621                        }
19622                        $userData['monthly_grp_id'] = $coupon['grp_id'];
19623                    }
19624
19625                    // add reserve payment amount
19626                    $wpPaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment($userId);
19627
19628                    // add appreciation lesson amount
19629                    $wpPaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.appreciation'));
19630
19631                    // add live lesson amount
19632                    $wpPaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.live'));
19633
19634                    $ncPaymentAmount = $wpPaymentAmount;
19635
19636                    // change payment method type to auth if amount to be paid in is equal to 0
19637                    if ($wpPaymentAmount == 0) {
19638                        $paymentMethodType = $paymentMethod . '_auth';
19639                        $wpPaymentAmount = $nominalAmountArr[$currencyCode];
19640                    }
19641
19642                    $tokenReason = 'Payment Credit Retry';
19643                    break;
19644                case Configure::read('payment_credit_force_charge'):
19645                    // get payment data
19646                    $paymentData = $this->PaymentPlanPrice->getPaymentData(array(
19647                        'currencyCode' => $currencyCode,
19648                        'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
19649                        'logFileName' => $logFileName
19650                    ));
19651
19652                    // throw error exception if does not exist
19653                    if (!$paymentData) {
19654                        $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Payment plan does not exist. - payment_credit_force_charge', 'error');
19655                        throw new InternalErrorException("Payment plan does not exist.");
19656                    }
19657
19658                    $wpPaymentAmount = $paymentData['amount'];
19659                    $priceId = $paymentData['priceId'];
19660                    $paymentPlanId = $paymentData['paymentPlanId'];
19661
19662                    // add reserve payment amount
19663                    $wpPaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment($userId);
19664
19665                    // add live lesson payment amount
19666                    $wpPaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment( $userId, false, Configure::read('appreciation_data.payment_element_type') );
19667                    
19668                    // add live lesson payment amount
19669                    $wpPaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.live'));                    
19670
19671                    $ncPaymentAmount = $wpPaymentAmount;
19672
19673                    // change payment method type to auth if amount is  equal to 0
19674                    if ($wpPaymentAmount == 0) {
19675                        $paymentMethodType = $paymentMethod . '_auth';
19676                        $wpPaymentAmount = $nominalAmountArr[$currencyCode];
19677                    }
19678
19679                    $tokenReason = 'Payment Credit Charge';
19680                    break;
19681            }
19682
19683            $currencyExponents = Configure::read('worldpay.currency_exponents');
19684            $exponent = $currencyExponents[$currencyCode];
19685
19686            // before coupon settlement amount deduction
19687            $beforeCouponSettlementAmount = $ncPaymentAmount;
19688
19689            // NJ-32737
19690            $couponData = $this->Session->read('apply_coupon_usage_data');
19691
19692            $membershipStatusIndex = UserTable::getStudentMembershipStatus($userId);
19693            if (in_array($membershipStatusIndex, Configure::read('allow_coupon.settlement')) &&
19694                isset($formType) &&
19695                in_array($formType, Configure::read('allow_coupon.settlement_form_type'))
19696            ) {
19697                // confiscate the coupon pending request when student is re-enrolled
19698                $res_confiscate = $this->UsersCouponV1->confiscateAllCoupon(array(
19699                    'userId' => $userId,
19700                    'action_type' => 1 // only the pending request will be confiscated
19701                ));
19702                
19703                if (!$res_confiscate) {
19704                    $this->log(__METHOD__ . ' Failed to confiscate coupon pending request. User id --> ' . $userId, $logFileName);
19705                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to confiscate coupon pending request. User id --> ' . $userId, 'error');
19706                }
19707
19708                if (isset($couponData['useCouponAmount']) && $couponData['useCouponAmount'] > 0) {
19709                    if ($wpPaymentAmount >= $couponData['useCouponAmount']) {
19710                        $wpPaymentAmount -= $couponData['useCouponAmount'];
19711                        $ncPaymentAmount -= $couponData['useCouponAmount'];
19712                    } else {
19713                        $wpPaymentAmount = 0;
19714                        $ncPaymentAmount = 0;
19715                    }
19716
19717                    // change niminal amount if amount is  equal to 0
19718                    if ($wpPaymentAmount == 0) {
19719                        $wpPaymentAmount = $nominalAmountArr[$currencyCode];
19720                    }
19721
19722                    $couponUseSettlement = $couponData;
19723                }
19724            }
19725            // NJ-32737-end
19726
19727            // get total amount with checking currency exponent
19728            $totalAmountArr = myTools::wpGetAmount($exponent, $wpPaymentAmount);
19729            $wpPaymentAmount = $totalAmountArr['wpAmount'];
19730
19731            $merchantCode = myTools::getWPMerchantCode($paymentMethodType);
19732
19733            $paymentParams = array(
19734                'currencyCode' => $currencyCode,
19735                'formType' => $formType,
19736                'logFileName' => $logFileName,
19737                'remoteAddress' => $_SERVER["REMOTE_ADDR"],
19738                'cardToken' => isset($userData['card_token']) ? $userData['card_token'] : null,
19739                'newCard' => true,
19740                'merchantCode' => $merchantCode,
19741                'wpPaymentAmount' => $wpPaymentAmount,
19742                'paymentAmount' => $ncPaymentAmount,
19743                'priceId' => $priceId,
19744                'paymentPlanId' => $paymentPlanId,
19745                'paymentType' => Configure::read('payment_types.payment_plan')
19746            );
19747
19748            if (!empty($couponUseSettlement)) {
19749                $paymentParams['couponUseSettlement'] = $couponUseSettlement;
19750            }
19751            
19752            if (!empty($coupon) && isset($formType) && $formType == Configure::read('payment_credit_retry') && !empty($userData['monthlyDiscount']) && !empty($userData['monthly_grp_id'])) {
19753                $paymentParams['discounted_amount'] = $userData['monthlyDiscount'];
19754                $paymentParams['monthlyDiscount'] = $userData['monthlyDiscount'];
19755                $paymentParams['monthly_grp_id'] = $userData['monthly_grp_id'];
19756            }
19757
19758            if (isset($postData['userRegister']) && $postData['userRegister']) {
19759                $paymentParams['userRegister'] = true;
19760            }
19761
19762            // NJ-42971: free trial checker
19763            $notFreeTrial = true;
19764
19765            if ($formType != Configure::read('payment_credit_change')) {
19766                $membershipTypes = UserTable::getEngMembershipTypeData();
19767                $statusAfter = $membershipTypes[1]; // premium plan paid
19768
19769                /* -- get before status -- */
19770                if ($this->memcache->get('com_plan_user_' . $userId) && $userData && $userData['payment_plan_id'] == Configure::read('payment_plans.complimentary_plan')) {
19771                    $statusBefore = $membershipTypes[15]; // complimentary code
19772                    $paymentParams['bonusCoinFlg'] = 1;
19773                    $paymentParams['updateFirstChargeDate'] = true;
19774                } elseif ($userData['charge_flg'] == 0) {
19775                    // failed settlement
19776                    if ($userData['fail_flg'] == 1) {
19777                        $statusBefore = $membershipTypes[5];
19778                    // trial again
19779                    } elseif ($userData['fail_flg'] == 0 && $userData['double_check_flg'] == 1) {
19780                        $statusBefore = $membershipTypes[13];
19781                        $notFreeTrial = false;
19782                    // unsubscribed
19783                    } elseif ($userData['fail_flg'] == 0 && $userData['double_check_flg'] == 2) {
19784                        $statusBefore = $membershipTypes[12];
19785                    // temporary
19786                    } elseif ($userData['status'] == 0) {
19787                        $statusBefore = $membershipTypes[6];
19788                        $statusAfter = $membershipTypes[2]; // premium plan free
19789                    } else {
19790                        $statusBefore = null;
19791                    }
19792                }
19793
19794                if (isset($statusBefore)) {
19795                    $user = new UserTable($userData);
19796                    $membershipTypeIndex = $user->getMembershipTypeIndex();
19797
19798                    if ($membershipTypeIndex == 13) {
19799                        $statusBefore = $membershipTypes[13];
19800                        $paymentParams['userRegister'] = true;
19801                        $notFreeTrial = false;
19802                        $statusAfter = $membershipTypes[2];
19803                    }
19804
19805                    // get platform use
19806                    $platform = myTools::mobappDetectPlatform();
19807                    $paymentParams['platform'] = $platform == Configure::read('platform.splp') ? Configure::read('platform.pclp') : $platform;
19808                    $paymentParams['statusBefore'] = $statusBefore;
19809                    $paymentParams['statusAfter'] = $statusAfter;
19810
19811                    $user = new UserTable($userData);
19812                    $membershipTypeIndex = $user->getMembershipTypeIndex();
19813
19814                    if ($membershipTypeIndex == 13) {
19815                        $paymentParams['userRegister'] = true;
19816                    }
19817                }
19818            }
19819
19820            $ptParams = array(
19821                'user_id' => $userId,
19822                'payment_hash' => $orderCode,
19823                'status' => $status,
19824                'payment_params' => json_encode($paymentParams),
19825                'course_id' => Configure::read("credit.course_id")
19826            );
19827
19828            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Before WP Payment Transaction Creation - Params --> ' . json_encode($ptParams), 'error');
19829
19830            // throw exception if failed to save payment transaction
19831            if (!$pt = $this->PaymentTransaction->setWPPaymentTransaction($ptParams)) {
19832                $this->log(__METHOD__ .' Failed to save payment transaction. update data --> ' . json_encode($ptParams), $logFileName);
19833                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to save payment transaction. update data --> ' . json_encode($ptParams), 'error');
19834                throw new InternalErrorException("Failed to save payment transaction.");
19835            }
19836
19837            $this->Session->write('wp_coupon_settlement_payment', [
19838                'payment_hash' => $pt['payment_hash'],
19839                'payment_amount' => $beforeCouponSettlementAmount // set before coupon settlement amount
19840            ]);
19841
19842            $wpData = array(
19843                'merchantCode' => $merchantCode,
19844                'orderCode' => $orderCode,
19845                'installationId' => Configure::read('worldpay.default_installation_id'),
19846                'currencyCode' => $currencyCode,
19847                'exponent' => $exponent,
19848                'amount' => $wpPaymentAmount,
19849                'email' => $userData['email'],
19850                'authenticatedShopperId' => $userId,
19851                'tokenEventReference' => $orderCode,
19852                'tokenReason' => $tokenReason,
19853                'xmlName' => 'hosted_reference_url',
19854                'paymentMethod' => $paymentMethod
19855            );
19856
19857            $this->log('getHostedReferenceUrl -- ' . json_encode($wpData), $logFileName);
19858            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Before getHostedReferenceUrl --> ' . json_encode($wpData), 'error');
19859
19860            $result = wpPaymentService::getHostedReferenceUrl($wpData);
19861            $hostedUrl = null;
19862            if (isset($result['paymentService']) && is_array($result['paymentService'])) {
19863                if (isset($result['paymentService']['reply']) && is_array($result['paymentService']['reply'])) {
19864                    if (isset($result['paymentService']['reply']['orderStatus']) && is_array($result['paymentService']['reply']['orderStatus'])) {
19865                        if (isset($result['paymentService']['reply']['orderStatus']['reference']) && is_array($result['paymentService']['reply']['orderStatus']['reference'])) {
19866                            if (isset($result['paymentService']['reply']['orderStatus']['reference']['@'])) {
19867                                $hostedUrl = $result['paymentService']['reply']['orderStatus']['reference']['@'];
19868                            }
19869                        }
19870                    }
19871                }
19872            }
19873
19874            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - After getHostedReferenceUrl --> ' . json_encode($result), 'error');
19875
19876            // if hostedUrl is null, set payment transaction status to 2
19877            if (!isset($hostedUrl)) {
19878                $status = 2; // error
19879            }
19880
19881            $updateData = array(
19882                'id' => $pt['id'],
19883                'fields' => array(
19884                    'response_text' => array('hostedReferenceUrl_response' => $result),
19885                    'status' => $status
19886                ),
19887                'logFileName' => $logFileName
19888            );
19889
19890            // redirect to retry page if failed to update payment transaction
19891            if (!$this->updatePaymentTransaction($updateData)) {
19892                $this->log(__METHOD__ .' Failed to update payment transaction. update data --> ' . json_encode($updateData), $logFileName);
19893                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to update payment transaction. update data --> ' . json_encode($updateData), 'error');
19894                throw new InternalErrorException("Failed to update payment transaction.");
19895            }
19896
19897            // throw exception if unable to generate hosted URL
19898            if (!isset($hostedUrl)) {
19899                $this->autoRender = $this->layout = false;
19900                myTools::parseAndSetWPErrorResponse(array(
19901                    'apiToken' => $apiToken,
19902                    'wpResponse' => $result,
19903                    'memKey' => $memKeyError
19904                ));
19905                $this->log(__METHOD__ .' Unable to generate hosted URL. get hosted url response --> ' . json_encode($ptParams), $logFileName);
19906                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Unable to generate hosted URL. get hosted url response  --> ' . json_encode($ptParams), 'error');
19907                throw new NotFoundException("Unable to generate hosted URL.");
19908            }
19909
19910            if ($formType == Configure::read('payment_credit_authentication')) {
19911                //NJ-13482
19912                $this->Session->write('reenroll_native_option', true);
19913            }
19914
19915            //    NC-7644 Add code reward for re-enroolling with the campaign code
19916            if($formType == Configure::read('payment_credit_force_charge')){
19917                $this->addCoinRewardForReenroll($userData);
19918            }
19919            
19920            // Teacher Perks : Student re-enroll
19921            if ( $formType == Configure::read('payment_credit_force_charge')) {
19922                ClassRegistry::init('TeacherPerksAccount')->reEnroll(['user_id' => $userData['id']]);
19923            }
19924
19925            $this->set('logFileName', $logFileName);
19926            $this->set('apiToken', $apiToken);
19927            $this->set('successUrl', $successUrl);
19928            $this->set('referrer', $referrer);
19929            $this->set('hostedUrl', $hostedUrl);
19930            $this->set('ncTerminalType', isset($postData['ncTerminalType']) ? $postData['ncTerminalType'] : 0);
19931
19932        // throw exception if method used is not POST
19933        } else {
19934            $this->log(__METHOD__ . ' Method used is not POST --> ' . json_encode($postData), 'debug');
19935            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Method used is not POST --> ' . json_encode($postData), 'error');
19936            throw new MethodNotAllowedException("Method used is not POST.");
19937        }
19938
19939        $this->render('/Elements/mobapp/wp_get_hosted_page');
19940    }
19941
19942    /**
19943     * NC-4770: Delete user previous card token use in wp
19944     * @param array $params
19945     * @return array $res
19946     */
19947    public function deleteUserToken($params = array()) {
19948        $result = wpPaymentService::deleteUserToken($params['deleteTokenParams']);
19949        $deleteToken = isset($result['paymentService']['reply']['ok']['deleteTokenReceived']) ? true : false;
19950
19951        // log if failed to delete token in wp
19952        if (!$deleteToken) {
19953            $this->log(__METHOD__ . ' Failed to delete user wp card token. params --> ' . json_encode($params['deleteTokenParams']) . ", error(s) --> " . $deleteTokenResultJson .' | kickback data --> ' . $params['dataJson'], $params['logFileName']);
19954        }
19955
19956        return $result;
19957    }
19958
19959    /**
19960     * NC-4770: worldpay memcache payment transaction and etc.
19961     * @param array $params
19962     */
19963    private function memcacheWPPayment($params = array()) {
19964        // set to memcache
19965        $this->memcache->set(array(
19966            'key' => $params['memKey'],
19967            'value' => array(
19968                'withPaymentTransaction' => true,
19969                'hostedUrl' => isset($params['mc']['hostedUrl']) ? $params['mc']['hostedUrl'] : (isset($params['hostedUrl']) ? $params['hostedUrl'] : null),
19970                'orderCode' => isset($params['mc']['orderCode']) ? $params['mc']['orderCode'] : (isset($params['orderCode']) ? $params['orderCode'] : null),
19971                'ptId' => isset($params['mc']['ptId']) ? $params['mc']['ptId'] : (isset($params['ptId']) ? $params['ptId'] : null),
19972                'isUseNewCard' => isset($params['isUseNewCard']) ? $params['isUseNewCard'] : (isset($params['mc']['isUseNewCard']) ? $params['mc']['isUseNewCard'] : 0)
19973            ),
19974            'expire' => 3600 // 1 hr
19975        ));
19976    }
19977
19978    private function memcacheCardType($params = array()) {
19979        // memcache card type value
19980        $this->memcache->set(array(
19981            'key' => $params['key'],
19982            'value' => $params['value'],
19983            'expire' => 3600 // 1 hr
19984        ));
19985    }
19986
19987    /**
19988     * NC-4770: worldpay process payment transaction.
19989     * @param array $params
19990     * @return string 'ok' or exception
19991     */
19992    public function processWPPayment($params) {
19993        $logFileName = isset($params['logFileName']) ? $params['logFileName'] : 'debug';
19994        $orderCode = isset($params['data']['OrderCode']) ? $params['data']['OrderCode'] : '';
19995        $paymentStatusName = isset($params['data']['PaymentStatus']) ? $params['data']['PaymentStatus'] : '';
19996        $userId = isset($params['ptData']['user_id']) ? $params['ptData']['user_id'] : null;
19997
19998        if (
19999            !isset($params['data']) || !isset($params['ptData']) ||
20000            !isset($params['amount']) || !isset($params['userData'])
20001        ) {
20002            $msg = ' Missing parameters.';
20003            $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
20004            $this->log(__METHOD__ . ' ' . $msg . ' Parameters --> ' . json_encode($params), $logFileName);
20005            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' Parameters --> ' . json_encode($params), 'error');
20006            echo "[OK]"; exit;
20007        }
20008
20009        $membershipStatusIndex = UserTable::getStudentMembershipStatus($userId);
20010
20011        // set variables
20012        $data = $params['data'];
20013        $dataJson = json_encode($data);
20014        $dateNow = date("Y-m-d H:i:s");
20015        $paymentTransactionData = $params['ptData'];
20016        $cardCompany = Configure::read('card_company.worldpay');
20017        $amount = $params['amount'];
20018        $paymentStatus = 1;
20019        $typeId = 1;
20020        $platform = Configure::read('platform.pclp');
20021        $receivablePayment = $params['receivablePayment'];
20022        $appreciationReceivable = $params['appreciationReceivable'];
20023        $liveLessonReceivable = $params['liveLessonReceivable'];
20024        $ptPaymentParams = json_decode($paymentTransactionData['payment_params'], true);
20025        $currencyCode = isset($ptPaymentParams['currencyCode']) ? $ptPaymentParams['currencyCode'] : null;
20026        $ptResponseText = array('wp_kickback' => $data);
20027        $ptPassword = $paymentTransactionData['password'];
20028        $formType = $ptPaymentParams['formType'];
20029        $cronDateRun = $params['cronDateRun'];
20030        $userData = $params['userData'];
20031        $transactionIdentifier = $params['transactionIdentifier'];
20032        $merchantCode = isset($ptPaymentParams['merchantCode']) ? $ptPaymentParams['merchantCode'] : Configure::read('worldpay.merchant_code_usd');
20033        $paymentPlanId = isset($ptPaymentParams['paymentPlanId']) ? $ptPaymentParams['paymentPlanId'] : null;
20034        $paymentType = isset($ptPaymentParams['paymentType']) ? $ptPaymentParams['paymentType'] : null;
20035        $priceId = isset($ptPaymentParams['priceId']) ? $ptPaymentParams['priceId'] : null;
20036        $familyId = isset($ptPaymentParams['familyId']) ? $ptPaymentParams['familyId'] : null;
20037        $parentId = isset($userData['User']['parent_id']) ? $userData['User']['parent_id'] : $ptPaymentParams['parentId'];
20038        $discounted_amount = isset($ptPaymentParams['discounted_amount']) ? $ptPaymentParams['discounted_amount'] : 0;
20039
20040        // if using coupon during force settlement
20041        if (
20042            !empty($ptPaymentParams['couponUseSettlement']) && 
20043            !empty($ptPaymentParams['couponUseSettlement']['useCouponAmount']) && 
20044            in_array($formType, Configure::read('allow_coupon.settlement_form_type'))
20045        ) {
20046            $discounted_amount += $ptPaymentParams['couponUseSettlement']['useCouponAmount'];
20047        }
20048
20049        $userId = $familyId ? $familyId : $userId;
20050        $appreciationFlg = 0;
20051        $tipAmount = null;
20052
20053
20054        $currency_before = $currencyCode;
20055        $plan_before = $paymentPlanId;
20056        $membershipStatusIndex = isset($ptPaymentParams['membershipStatusIndex']) && $ptPaymentParams['membershipStatusIndex'] ? $ptPaymentParams['membershipStatusIndex'] : $membershipStatusIndex;
20057        $uModel = $this->User;
20058
20059        if (in_array($formType, array(Configure::read('payment_credit_retry'), Configure::read('payment_credit_authentication')))) {
20060            $typeId = 2;
20061        } 
20062
20063        if (isset($amount) && $amount < 0) {
20064            $typeId = 0;
20065        }
20066
20067        $userData = $userData['User'];
20068        $pModel = $this->Payment;
20069
20070        // check if family plan
20071        if (
20072            $familyId && 
20073            $parentId && 
20074            (
20075                in_array($formType, array(Configure::read('payment_credit_coin_purchase'), Configure::read('payment_credit_textbook_purchase'))) 
20076                ||
20077                (
20078                    isset($ptPaymentParams['nativeOptionJoin']) && 
20079                    $ptPaymentParams['nativeOptionJoin'] && 
20080                    $ptPaymentParams['formType'] == Configure::read('payment_native_option_join')
20081                )
20082                ||
20083                (
20084                    isset($ptPaymentParams['callanOptionJoin']) && 
20085                    $ptPaymentParams['callanOptionJoin'] && 
20086                    $ptPaymentParams['formType'] == Configure::read('payment_callan_option_join')
20087                )
20088            )
20089        ) {
20090            // change reference id to parent id
20091            $referenceId = $parentId;
20092        } else {
20093            $referenceId = $userId;
20094        }
20095
20096        // set variables
20097        $paymentData = array(
20098            'user_id' => $userId,
20099            'type_id' => $typeId,
20100            'reference_id' => $referenceId,
20101            'payment_transaction_password' => $ptPassword,
20102            'status' => $paymentStatus,
20103            'form_type' => $formType,
20104            'ordd' => $orderCode,
20105            'amount' => $amount,
20106            'param1' => $dataJson,
20107            'card_company' => $cardCompany,
20108            'transaction_code' => $orderCode,
20109            'currency_code' => $currencyCode,
20110            'payment_id' => $paymentPlanId,
20111            'price_id' => $priceId,
20112            'payment_type' => $paymentType,
20113        );
20114        
20115        $discountType = 'monthly';
20116        if ($formType == Configure::read('payment_native_option_join')) {
20117            $discountType = 'native';
20118        } else if ($formType == Configure::read('payment_callan_option_join')) {
20119            $discountType = 'callan';
20120        } else if ($formType == Configure::read('payment_credit_coin_purchase')) {
20121            $discountType = 'coin';
20122        }
20123        
20124        // NJ-47740
20125        $getCouponDiscounDetail = PaymentTable::getCouponDiscountRequestDetail($ptPaymentParams, $discountType);
20126        $paymentData['discounted_amount'] = !empty($getCouponDiscounDetail['discounted_amount']) ? $getCouponDiscounDetail['discounted_amount'] : 0;
20127        $paymentData['coupon_request_id'] = !empty($getCouponDiscounDetail['coupon_request_id']) ? $getCouponDiscounDetail['coupon_request_id'] : null;
20128        
20129        $forceSettlementWithCoupon  = false;
20130        // if using coupon during force settlement
20131        if (
20132            !empty($ptPaymentParams['couponUseSettlement']) && 
20133            !empty($ptPaymentParams['couponUseSettlement']['useCouponAmount']) && 
20134            in_array($formType, Configure::read('allow_coupon.settlement_form_type'))
20135        ) {
20136            // apply coupon use discount
20137            $couponData = $ptPaymentParams['couponUseSettlement'];
20138            $couponData['nextChargeDate'] = date('Y-m-d');
20139            $couponData['request_result'] = true;
20140
20141            $result_coupon_use = $this->UsersCouponV1->performCouponUse($couponData);
20142            $result_coupon_use = !empty($result_coupon_use) ? json_decode($result_coupon_use,true) : array();
20143
20144            if (empty($result_coupon_use)) {
20145                $this->log(__METHOD__ . ' Failed to used coupons.' . json_encode($couponData), $logFileName);
20146                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to used coupons.' . json_encode($couponData), 'error');
20147                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to used coupons.', $couponData, array_merge($_POST, $_SERVER));
20148                return false;
20149            }
20150            
20151            $paymentData['discounted_amount'] = $ptPaymentParams['couponUseSettlement']['useCouponAmount'];
20152            $paymentData['coupon_request_id'] = isset($result_coupon_use['cgrp_id']) ? $result_coupon_use['cgrp_id'] : null;
20153            
20154            $forceSettlementWithCoupon = true;
20155        }
20156        // NJ-47740 - end
20157        
20158        $discountOption = isset($ptPaymentParams['discountOption']) ? $ptPaymentParams['discountOption'] : [];
20159    
20160        if (!empty($discountOption)) {
20161            $paymentData['discount_option_price_id'] = $discountOption['discount_option_price_id'];
20162        }
20163            
20164        //- check payment receivable with zero amount
20165        if (
20166            $formType == Configure::read('payment_credit_receivable') &&
20167            $amount <= 0
20168        ) {
20169            //- skip saving
20170        } else {
20171            // create new payment
20172            $pModel->clear();
20173            $pModel->create();
20174            $pModel->validate = array();
20175            $pModel->set($paymentData);
20176
20177            // return if not save
20178            if (!$paymentSave = $pModel->save()) {
20179                $msg = 'Saving payment failed.';
20180                $this->log(__METHOD__ . ' ' . $msg . ' Payment data --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, $logFileName);
20181                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' Payment data --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, 'error');
20182                $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
20183                
20184                // if payment failed and has coupon grp id and its direct payment -> unconfirm coupon
20185                if (
20186                    isset($paymentData['coupon_request_id']) && $paymentData['coupon_request_id'] &&
20187                    (
20188                        // the native or callan purchase with coupon use already has checker while processing the payment
20189                        // to ensure that payment errors are caught, place it here as well to make sure that the coupon is unconfirmed in case the page is refreshed while processing
20190                        in_array(
20191                            $formType, array(
20192                                Configure::read('payment_native_option_join'),
20193                                Configure::read('payment_callan_option_join'),
20194                                Configure::read('payment_credit_coin_purchase')
20195                            )
20196                        ) ||
20197                        // force settlement with coupon
20198                        $forceSettlementWithCoupon
20199                    )
20200                ) {
20201                    $couponKbn = Configure::read('coupon_kbn.coin_purchase'); // default
20202                    if ($formType == Configure::read('payment_native_option_join')) {
20203                        $couponKbn = Configure::read('coupon_kbn.native_option');
20204                    } else if ($formType == Configure::read('payment_callan_option_join')) {
20205                        $couponKbn = Configure::read('coupon_kbn.callan_option');
20206                    } else if ($forceSettlementWithCoupon) {
20207                        $couponKbn = Configure::read('coupon_kbn.monthly_settlement');
20208                    }
20209                    
20210                    $res_unconfirm = $this->UsersCouponV1->performCouponUnconfirm(array(
20211                        'grpId' => $paymentData['coupon_request_id'],
20212                        'userId' => $userId,
20213                        'kbn' => $couponKbn
20214                    ));
20215
20216                    if (empty($res_unconfirm)) {
20217                        $this->log(__METHOD__ . ' failed to perform coupon unconfirm.', $logFileName);
20218                        $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - failed to perform coupon unconfirm.', 'error');
20219                    }
20220                }
20221                
20222                throw new InternalErrorException($msg);
20223            }
20224            //update/add user`s settlement amount
20225            $this->User->updateUserPayments($paymentData);
20226            $paymentId = $paymentSave['Payment']['id'];
20227
20228            // set payment_id
20229            $paymentSaveID = $this->Payment->id;
20230            
20231            // NJ-47740
20232            if (!empty($paymentData['coupon_request_id']) && $paymentData['discounted_amount'] > 0) {
20233                // confirm coupon use request for discount
20234                $requestCouponConfirmData = array(
20235                    'grpId' => $paymentData['coupon_request_id'],
20236                    'paymentId' => $paymentSaveID
20237                );
20238                $result_confirm = $this->UsersCouponV1->performCouponConfirm($requestCouponConfirmData);
20239                
20240                if (!$result_confirm) {
20241                    $msg = 'Failed to confirm coupon use request.';
20242                    $this->log(__METHOD__ . ' Failed to confirm coupon use request. ' . json_encode($requestCouponConfirmData) . ' -- ' . $dataJson, $logFileName);
20243                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to confirm coupon use request. ' . json_encode($requestCouponConfirmData) . ' -- ' . $dataJson, 'error');
20244                    $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
20245                    throw new InternalErrorException($msg);
20246                }
20247            }
20248            // NJ-47740 end
20249            
20250            // NJ-35237
20251            if (!empty($ptPaymentParams['rewardedPoints'])) {
20252                $rewaredPointParams['ContinuationRewardPoint'] = $ptPaymentParams['rewardedPoints'];
20253                // save reward point
20254                if (!$this->ContinuationRewardPoint->saveRewardPoint($rewaredPointParams)) {
20255                    $this->log(__METHOD__ . ' Failed to save reward point. --> ' . json_encode($ptPaymentParams['rewardedPoints']), $logFileName);
20256                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to save reward point. --> ' . json_encode($ptPaymentParams['rewardedPoints']), 'error');
20257                }
20258            }
20259            // NJ-35237 end
20260            
20261            // update payment details
20262            $updatePaymentDetailParams = array(
20263                'currencyCode' => $paymentData['currency_code'],
20264                'formType' => $paymentData['form_type'],
20265                'paymentType' => $paymentData['payment_type'],
20266                'amount' => $paymentData['amount'],
20267                'discounted_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0,
20268                'familyId' => $familyId,
20269                'cronDateRun' => $cronDateRun,
20270                'priceId' => $paymentData['price_id'],
20271                'paymentPlanId' => $paymentData['payment_id'],
20272                'user_id' => $paymentData['user_id'],
20273                'coupon_use_request_id' => isset($paymentData['coupon_request_id']) ? $paymentData['coupon_request_id'] : null,
20274                'coupon_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0
20275            );
20276            
20277            if (!empty($discountOption)) {
20278                $updatePaymentDetailParams['discount_option_price_id'] = $discountOption['discount_option_price_id'];
20279                $updatePaymentDetailParams['discount_option_amount'] = $discountOption['amount'];
20280            }
20281
20282            $updatePaymentDetail = array(
20283                'id' => $paymentTransactionData['id'],
20284                'fields' => array(
20285                    'payment_details' => $updatePaymentDetailParams
20286                )
20287            );
20288
20289            if (!$this->PaymentTransaction->updateWPPaymentTransaction($updatePaymentDetail)) {
20290                $this->log(__METHOD__ . ' Failed to update payment details. ' . json_encode($updatePaymentDetail), $logFileName);
20291                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to update payment details - on create new payment ' . json_encode($updatePaymentDetail), 'error');
20292            }
20293        }
20294
20295        // if payment was saved, and form type belongs to textbook purchase,
20296        // update textbook_sales table, insert payment_id
20297        if ($formType == Configure::read('payment_credit_textbook_purchase')) {
20298            // set textbook sales info
20299            $textbookSales = $this->TextbookSale->find('first', array(
20300                'conditions' => array(
20301                    'TextbookSale.sales_code' => $ptPassword
20302                ),
20303                'recursive' => -1
20304            ));
20305            
20306            // if has textbook sales, update payment_id
20307            if ($textbookSales) {
20308                $this->TextbookSale->clear();
20309                if (!$this->TextbookSale->read(null, $textbookSales['TextbookSale']['id'])) {
20310                    $msg = 'Textbook sales id does not exist.';
20311                    $this->log(__METHOD__ . ' ' . $msg . json_encode($textbookSales), $logFileName);
20312                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . json_encode($textbookSales), 'error');
20313                    $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
20314                    echo "[OK]"; exit;
20315                }
20316                $this->TextbookSale->set('payment_id', $paymentId);
20317                $this->TextbookSale->set('payment_status', 1);
20318                if (!$this->TextbookSale->save()) {
20319                    $msg = 'Failed to update textbook sales payment status to 1.';
20320                    $this->log(__METHOD__ . ' ' . $msg . json_encode($textbookSales), $logFileName);
20321                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . json_encode($textbookSales), 'error');
20322                    $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
20323                    throw new InternalErrorException($msg);
20324                }
20325            }
20326        }
20327
20328        // check if form type is not equals to textbook purchase or receivable
20329        if (
20330            $formType != Configure::read('payment_credit_coin_purchase') &&
20331            $formType != Configure::read('payment_credit_textbook_purchase') &&
20332            $formType != Configure::read('payment_credit_receivable') &&
20333            $formType != Configure::read('payment_credit_appreciation_receivable') &&
20334            $formType != Configure::read('payment_native_option_monthly_payment') &&
20335            $formType != Configure::read('payment_native_option_join') &&
20336            $formType != Configure::read('payment_callan_option_monthly_payment') &&
20337            $formType != Configure::read('payment_callan_option_join')
20338        ) {
20339            // set user array to be save
20340            $saveUserArr = array(
20341                'modified' => $dateNow,
20342                'fail_flg' => 0,
20343                'charge_flg' => 1,
20344                'counseling_attended_flg' => 0,
20345                'card_company' => $cardCompany,
20346                'hash16' => $userId,
20347                'last_charge_date' => $dateNow,
20348                'wp_transaction_identifier' => $transactionIdentifier,
20349                'payment_plan_id' => $paymentPlanId,
20350                'price_id' => $priceId
20351            );
20352            //NJ-7874 if appreciation flag and amount is set
20353            if (isset($ptPaymentParams['family_data']['applyPlan']['tip_max_amount']) && $ptPaymentParams['family_data']['applyPlan']['tip_max_amount']) {
20354                $tipAmount = $ptPaymentParams['family_data']['applyPlan']['tip_max_amount'];
20355            }
20356
20357            if (isset($ptPaymentParams['family_data']['applyPlan']['allow_appreciation_flg']) && $ptPaymentParams['family_data']['applyPlan']['allow_appreciation_flg'] && $tipAmount) {
20358                $appreciationFlg = 1;
20359            }
20360            // NJ-1562 - appreciation on
20361            if( $paymentPlanId && in_array( $paymentPlanId, Configure::read('appreciation.payment_plan_id') ) ) {
20362                $saveUserArr['allow_appreciation_flg'] = 1; // on
20363
20364                //NJ-7548 : 
20365                if (
20366                    !in_array($paymentPlanId,Configure::read('appreciation.can_coin_purchase_check')) &&
20367                    (
20368                        $formType == Configure::read('payment_credit_authentication') ||
20369                        $formType == Configure::read('payment_credit_change') || 
20370                        $formType == Configure::read('payment_credit_force_charge') || 
20371                        $formType == Configure::read('payment_credit_retry')
20372                    )
20373                ) {
20374                    //fetch the age
20375                    $userAge = UserTable::getStudentAge($userData['birthday']);
20376                    $userAge = $userAge ? (int) $userAge : null;
20377                    $showAppreciationFlg = 0;
20378
20379                    //change the show appreciation flg if no birthday set or 18 and above            
20380                    if (!$userAge || $userAge >= 18) {
20381                        $saveUserArr['show_appreciation_flg'] = 1; // on
20382                    }
20383                }
20384                //NJ-7874 set appreciation settings for Family Plan
20385                if (in_array($paymentPlanId, Configure::read('appreciation.can_coin_purchase_check')) ) {
20386                    $saveUserArr['allow_appreciation_flg'] = $appreciationFlg;
20387                    $saveUserArr['show_appreciation_flg'] = $appreciationFlg;
20388                    $saveUserArr['tip_max_amount'] = $tipAmount;
20389                }
20390            }
20391
20392            // check payment if credit authentication
20393            if (in_array($formType, array(Configure::read('payment_credit_authentication'), Configure::read('payment_credit_family_free'))) 
20394                || isset($ptPaymentParams['updateFirstChargeDate'])
20395            ) {
20396                $saveUserArr['first_charge_date'] = $dateNow;
20397                // $saveUserArr['platform'] = $platform;
20398            }
20399
20400            // if bonus coin flg is set
20401            if (isset($ptPaymentParams['bonusCoinFlg'])) {
20402                $saveUserArr['bonus_coin_flg'] = $ptPaymentParams['bonusCoinFlg'];
20403            }
20404
20405            // get time today plus 1 hour
20406            $nextChargeTime = (time() + 3600) - strtotime('TODAY');
20407
20408            // check if subscription payment
20409            if (
20410                $formType == Configure::read('payment_credit_force_charge') ||
20411                $formType == Configure::read('payment_credit_retry') ||
20412                $formType == Configure::read('payment_credit_monthly_payment') ||
20413                $formType == Configure::read('payment_credit_family_monthly_payment') ||
20414                $formType == Configure::read('payment_credit_family_free')
20415            ) {
20416
20417                if ($formType == Configure::read('payment_credit_monthly_payment')) {
20418                    $nextChargeTime = strtotime($userData['next_charge_date']) - strtotime('TODAY');
20419                }
20420
20421                // set minutes and seconds to 00:00 always
20422                $nextChargeDate = date('Y-m-d H:00:00', strtotime('+' . $nextChargeTime . ' second ' . $this->User->getNextChargeDate()));
20423                $saveUserArr['next_charge_date'] = $nextChargeDate;
20424                $saveUserArr['double_check_flg'] = 1;
20425                $saveUserArr['expired_card_flg'] = 0;
20426
20427                // give points to user join the campaign who retry payment
20428                if ($formType == Configure::read('payment_credit_retry')) {
20429                    $this->ContinuationCampaign->givePointsRetrySuccess(array(
20430                        'user_ids' => array($userId)
20431                    ));
20432                }
20433
20434                if ($formType == Configure::read('payment_credit_family_free')) {
20435                    $nextChargeDate = date('Y-m-d H:00:00', strtotime('+' . $nextChargeTime . ' second ' . $this->User->getFirstNextChargeDate()));
20436                    $saveUserArr['next_charge_date'] = $nextChargeDate;
20437                }
20438
20439                // give points if user join campaign and success payment
20440                if ($formType == Configure::read('payment_credit_monthly_payment')) {
20441                    $this->ContinuationCampaign->givePoints(array(
20442                        'user_id' => $userId
20443                    ));
20444                }
20445
20446                // Worldpay: sync all add child behaviour -> set next charge date to current hour
20447                if ($formType == Configure::read('payment_credit_family_monthly_payment')) {
20448                    $nextChargeDate = date('Y-m-d H:00:00', strtotime('+' . (time() - strtotime('TODAY')) . ' second ' . $this->User->getNextChargeDate()));
20449                    $saveUserArr['next_charge_date'] = $nextChargeDate;
20450                }
20451
20452
20453                # give coins if temporary/new user is changed/added to family plan
20454                if ($formType == Configure::read('payment_credit_family_free') && $userData['status'] == 0) {
20455                    // NJ-4746: defult bonus point
20456                    $defaultBC = ClassRegistry::init("DefaultCoinRegistration")->defaultCoins();
20457                    $bonusPoints = (($defaultBC > 0) ? $defaultBC : Configure::read("credit.bonus_coin_authentication"));
20458
20459                    // camapaign master triiger 1
20460                    $campaignMaster = ClassRegistry::init('CampaignMaster')->bonusTrigger(['userId' => $userData['id'], 'triggerNo' => 1]);
20461                    if (!$campaignMaster['bonusCoins'] && !$campaignMaster['bonusCoupons']) {
20462                        # add to the user's existing coin
20463                        $pointParams = array(
20464                            'userId' => $userData['id'],
20465                            'point' => $bonusPoints,
20466                            'kbn' => Configure::read("point_history.bonus"),
20467                            'kbnType' => 1, // add coin
20468                            'coinType' => 2, // service coin
20469                            'coinFailMessage' => Configure::read('coin.failed.campaign')
20470                        );
20471                        if (!$this->UsersPoint->performPointTransaction($pointParams)) {
20472                            $msg = 'Failed add point to user.';
20473                            $this->log(__METHOD__ . ' Failed add point to user. ' . json_encode($pointParams) . ' -- ' . json_encode($data), $logFileName);
20474                            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed add point to user. ' . json_encode($pointParams) . ' -- ' . json_encode($data), 'error');
20475                            $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
20476                            return ;
20477                        }
20478                    }
20479                }
20480                // NJ-66191 Add logger for next_charge_date
20481                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Attempt to change next_charge_date --> ' . json_encode(['order_code' => $orderCode, 'old_next_charge_date' => $userData['next_charge_date'] ?? null, 'new_next_charge_date' => $saveUserArr['next_charge_date']]), $logFileName);
20482                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Attempt to change next_charge_date --> ' . json_encode(['order_code' => $orderCode, 'old_next_charge_date' => $userData['next_charge_date'] ?? null, 'new_next_charge_date' => $saveUserArr['next_charge_date']]), 'error');
20483
20484            } elseif ($formType == Configure::read('payment_credit_authentication')) {
20485                // set minutes and seconds to 00:00 always
20486                $nextChargeDate = date('Y-m-d H:00:00', strtotime('+' . $nextChargeTime . ' second ' . $this->User->getFirstNextChargeDate()));
20487                $saveUserArr['next_charge_date'] = $nextChargeDate;
20488                // NJ-66191 Add logger for next_charge_date
20489                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Attempt to change next_charge_date --> ' . json_encode(['order_code' => $orderCode, 'old_next_charge_date' => $userData['next_charge_date'] ?? null, 'new_next_charge_date' => $saveUserArr['next_charge_date']]), $logFileName);
20490                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Attempt to change next_charge_date --> ' . json_encode(['order_code' => $orderCode, 'old_next_charge_date' => $userData['next_charge_date'] ?? null, 'new_next_charge_date' => $saveUserArr['next_charge_date']]), 'error');
20491                
20492                if (isset($ptPaymentParams['userRegister']) && $ptPaymentParams['userRegister']) {
20493                    $stepKey = Configure::read('registration_steps.credit_card_registration_success');
20494                     $this->memcache->set(array(
20495                        'key' => 'wp_register_completed_'.$userId,
20496                        'value' => true,
20497                        'expire' => 120
20498                    ));
20499                    $this->saveStep($userId, $stepKey);
20500                }
20501            }
20502
20503            // if credit card change from android or apple to worldpay
20504            if (
20505                in_array($formType, array(Configure::read('payment_credit_change'), Configure::read('payment_credit_authentication'))) &&
20506                in_array($cardCompany, array(Configure::read('card_company.apple'), Configure::read('card_company.google')))
20507            ) {
20508
20509
20510                $pointParams = array(
20511                    'userId' => $userId,
20512                    'point' => 500,
20513                    'kbn' => 6,
20514                    'kbnType' => 1, // add coin
20515                    'coinType' => 2, // service coin
20516                    'coinFailMessage' => Configure::read('coin.failed.campaign')
20517                );
20518
20519                if (!$this->UsersPoint->performPointTransaction($pointParams)) {
20520                    $msg = 'Adding user coin history failed.';
20521                    $this->log(__METHOD__ . ' ' . $msg . ' Point params --> ' . json_encode($pointParams) . ' | kickback data --> ' . $dataJson, $logFileName);
20522                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' Point params --> ' . json_encode($pointParams) . ' | kickback data --> ' . $dataJson, 'error');
20523                    $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
20524                    throw new InternalErrorException($msg);
20525                }
20526            }
20527
20528            $famRegist = false;
20529            // NC-4673: update family parent_id, memo and monthly_payment
20530            
20531            if (
20532                in_array($formType, Configure::read('family_plan_form_types'))
20533            ) {
20534                // if parent_id is empty
20535                if (empty($userData['parent_id'])) {
20536                    $saveUserArr['parent_id'] = $parentId;
20537                    $saveUserArr['memo'] = date('Y/m/d H:i:s')." Family plan[User]: family registration \n".$userData['memo'];
20538                    $famRegist = true;
20539
20540                    if (empty($userData['currency_code'])) {
20541                        $saveUserArr['currency_code'] = $currencyCode;
20542                    }
20543                }
20544            }
20545
20546            // get and set card token, card brand and card number
20547            // if not new registration, delete wp token
20548            if (
20549                $formType == Configure::read('payment_credit_change') ||
20550                ($formType == Configure::read('payment_credit_authentication') && isset($ptPaymentParams['newCard']) && $ptPaymentParams['newCard']) ||
20551                ($formType == Configure::read('payment_credit_retry') && isset($ptPaymentParams['newCard']) && $ptPaymentParams['newCard']) ||
20552                ($formType == Configure::read('payment_credit_force_charge') && isset($ptPaymentParams['newCard']) && $ptPaymentParams['newCard']) ||
20553                $formType == Configure::read('payment_credit_family_free') ||
20554                $formType == Configure::read('payment_credit_family_monthly_payment')
20555            ) {
20556                // if family plan payment use parent id
20557                if($formType == Configure::read('payment_credit_family_free') || $formType == Configure::read('payment_credit_family_monthly_payment')){
20558                    $authenticatedShopperId = $parentId;
20559                }else{
20560                    $authenticatedShopperId = $userId;
20561                }
20562
20563                $cardInfoParams = array(
20564                    'merchantCode' => $merchantCode,
20565                    'authenticatedShopperId' => $authenticatedShopperId,
20566                    'xmlName' => 'card_info'
20567                );
20568
20569                $cardInfo = wpPaymentService::getUserCardInfo($cardInfoParams);
20570                $ptResponseText['getUserCardInfo_response'] = $cardInfo;
20571                $cardToken = null;
20572                $cardDetails = array();
20573
20574                // user has only 1 token
20575                if (isset($cardInfo['paymentService']['reply']['token']['tokenDetails'])) {
20576                    $cardTokenDetails = $cardInfo['paymentService']['reply']['token']['tokenDetails'];
20577                    $cardToken = $cardTokenDetails['paymentTokenID'];
20578
20579                    // get card number and card brand
20580                    $cardDetails = isset($cardInfo['paymentService']['reply']['token']['paymentInstrument']['cardDetails']['derived']) ? $cardInfo['paymentService']['reply']['token']['paymentInstrument']['cardDetails']['derived'] : array();
20581
20582                    // - if has no card details, check other payment instru
20583                    if (!$cardDetails) {
20584                        // - paypal
20585                        if (isset($cardInfo['paymentService']['reply']['token']['paymentInstrument']['paypal']['derived'])) {
20586                            $cardDetails = $cardInfo['paymentService']['reply']['token']['paymentInstrument']['paypal']['derived'];
20587                        }
20588
20589                        // - emvco token
20590                        if (isset($cardInfo['paymentService']['reply']['token']['paymentInstrument']['emvcoTokenDetails']['derived'])) {
20591                            $cardDetails = $cardInfo['paymentService']['reply']['token']['paymentInstrument']['emvcoTokenDetails']['derived'];
20592                        }
20593
20594                        // - sepa
20595                        if (isset($cardInfo['paymentService']['reply']['token']['paymentInstrument']['sepa']['derived'])) {
20596                            $cardDetails = $cardInfo['paymentService']['reply']['token']['paymentInstrument']['sepa']['derived'];
20597                        }
20598                    }
20599
20600                    // NJ-62324
20601                    // If change card, and old card details is the same as new one, update user token
20602                    $newCardNumber = substr($cardDetails['obfuscatedPAN'], -4);
20603                    $newCardBrand = $cardDetails['cardBrand'];
20604                    $oldCardNumber = isset($userData['card_number']) ? $userData['card_number'] : 0;
20605                    $oldCardBrand = isset($userData['card_brand']) ? $userData['card_brand'] : 0;
20606                    $oldCardToken = isset($userData['card_token']) ? $userData['card_token'] : 0;
20607
20608                    $expiryMonth = isset($cardInfo['paymentService']['reply']['token']['paymentInstrument']['cardDetails']['expiryDate']['date']['@month']) ? $cardInfo['paymentService']['reply']['token']['paymentInstrument']['cardDetails']['expiryDate']['date']['@month'] : null;
20609                    $expiryYear = isset($cardInfo['paymentService']['reply']['token']['paymentInstrument']['cardDetails']['expiryDate']['date']['@year']) ? $cardInfo['paymentService']['reply']['token']['paymentInstrument']['cardDetails']['expiryDate']['date']['@year'] : null;
20610
20611                    // NJ-62324: for debugging
20612                    $debugWPayTokenData = array(
20613                        'newCardNumber' => $newCardNumber,
20614                        'newCardBrand' => $newCardBrand,
20615                        'oldCardNumber' => $oldCardNumber,
20616                        'oldCardBrand' => $oldCardBrand,
20617                        'oldCardToken' => $oldCardToken,
20618                        'newCardToken' => $cardToken,
20619                        'expiryMonth' => $expiryMonth,
20620                        'expiryYear' => $expiryYear
20621                    );
20622                    $this->log(__METHOD__ . ' Reply Worldpay Update Token Data Attempt -> ' . $authenticatedShopperId . ' -> ' . json_encode($debugWPayTokenData), $logFileName);
20623
20624                    if (
20625                        $expiryMonth && $expiryYear && 
20626                        ( ($newCardNumber == $oldCardNumber && $newCardBrand == $oldCardBrand) || ($cardToken == $oldCardToken) )
20627                    ) {
20628                        // always 2 digits, example 01, 02, 03
20629                        $expiryMonth = str_pad($expiryMonth, 2, '0', STR_PAD_LEFT); 
20630                        $updateTokenParams = array(
20631                            'merchantCode' => $merchantCode,
20632                            'paymentTokenId' => $cardToken,
20633                            'authenticatedShopperId' => $userId,
20634                            'xmlName' => 'update_token',
20635                            'expiryMonth' => $expiryMonth,
20636                            'expiryYear' => $expiryYear,
20637                            'orderCode' => $orderCode,
20638                            'tokenReason' => 'Payment Credit Change'
20639                        );
20640                        $ptResponseText['updateUserToken_request'][] = $updateTokenParams;
20641                        $this->log(__METHOD__ . ' New Expiry Date Update Token -> ' . $authenticatedShopperId . ' -> ' . json_encode($updateTokenParams), $logFileName);
20642
20643                        // update latest token only
20644                        $ptResponseText['updateUserToken_response'][] =  $this->updateUserToken(array(
20645                            'updateTokenParams' => $updateTokenParams,
20646                            'logFileName' => $logFileName,
20647                            'dataJson' => $dataJson,
20648                            'ptId' => $paymentTransactionData['id']
20649                        ));
20650                    }
20651
20652                // user has many token
20653                } elseif (isset($cardInfo['paymentService']['reply']['token'][0])) {
20654                    $cardTokenDetails = $cardInfo['paymentService']['reply']['token'];
20655
20656                    $getCardDetailFlg = 0;
20657                    $countTokenDetails = count($cardTokenDetails) - 1;
20658                    foreach ($cardTokenDetails as $key => $value) {
20659                        if (
20660                            (
20661                                $formType == Configure::read('payment_credit_change') && 
20662                                (isset($ptPaymentParams['newCard']) && $ptPaymentParams['newCard']) && 
20663                                (isset($ptPaymentParams['cardToken']) && $ptPaymentParams['cardToken']) &&
20664                                $value['tokenDetails']['paymentTokenID'] != $ptPaymentParams['cardToken'] &&
20665                                $getCardDetailFlg == 0
20666                            ) || 
20667                            (
20668                                $formType == Configure::read('payment_credit_change') &&
20669                                $key == $countTokenDetails && 
20670                                $getCardDetailFlg == 0
20671                            )
20672                        ) {
20673                            
20674                            // - get card details
20675                            $cardToken = $value['tokenDetails']['paymentTokenID'];
20676                            $cardDetails = isset($value['paymentInstrument']['cardDetails']['derived']) ? $value['paymentInstrument']['cardDetails']['derived'] : array();
20677                            
20678                            // - if has no card details, check other payment instru
20679                            if (!$cardDetails) {
20680                                // - paypal
20681                                if (isset($cardInfo['paymentService']['reply']['token']['paymentInstrument']['paypal']['derived'])) {
20682                                    $cardDetails = $cardInfo['paymentService']['reply']['token']['paymentInstrument']['paypal']['derived'];
20683                                }
20684
20685                                // - emvco token
20686                                if (isset($cardInfo['paymentService']['reply']['token']['paymentInstrument']['emvcoTokenDetails']['derived'])) {
20687                                    $cardDetails = $cardInfo['paymentService']['reply']['token']['paymentInstrument']['emvcoTokenDetails']['derived'];
20688                                }
20689                                
20690                                // - sepa
20691                                if (isset($cardInfo['paymentService']['reply']['token']['paymentInstrument']['sepa']['derived'])) {
20692                                    $cardDetails = $cardInfo['paymentService']['reply']['token']['paymentInstrument']['sepa']['derived'];
20693                                }
20694                            }
20695                            $getCardDetailFlg = 1;
20696
20697                            // NJ-62324
20698                            // If change card, and old card details is the same as new one, update latest token only
20699                            $newCardNumber = substr($cardDetails['obfuscatedPAN'], -4);
20700                            $newCardBrand = $cardDetails['cardBrand'];
20701                            $oldCardNumber = isset($userData['card_number']) ? $userData['card_number'] : 0;
20702                            $oldCardBrand = isset($userData['card_brand']) ? $userData['card_brand'] : 0;
20703                            $oldCardToken = isset($userData['card_token']) ? $userData['card_token'] : 0;
20704
20705                            $expiryMonth = isset($value['paymentInstrument']['cardDetails']['expiryDate']['date']['@month']) ? $value['paymentInstrument']['cardDetails']['expiryDate']['date']['@month'] : null;
20706                            $expiryYear = isset($value['paymentInstrument']['cardDetails']['expiryDate']['date']['@year']) ? $value['paymentInstrument']['cardDetails']['expiryDate']['date']['@year'] : null;
20707    
20708                            // NJ-62324: for debugging
20709                            $debugWPayTokenData = array(
20710                                'newCardNumber' => $newCardNumber,
20711                                'newCardBrand' => $newCardBrand,
20712                                'oldCardNumber' => $oldCardNumber,
20713                                'oldCardBrand' => $oldCardBrand,
20714                                'oldCardToken' => $oldCardToken,
20715                                'newCardToken' => $cardToken,
20716                                'expiryMonth' => $expiryMonth,
20717                                'expiryYear' => $expiryYear
20718                            );
20719                            $this->log(__METHOD__ . ' Reply Worldpay Update Token Data Attempt -> ' . $authenticatedShopperId . ' -> ' . json_encode($debugWPayTokenData), $logFileName);
20720
20721                            if (
20722                                $expiryMonth && $expiryYear && 
20723                                ( ($newCardNumber == $oldCardNumber && $newCardBrand == $oldCardBrand) || ($cardToken == $oldCardToken) )
20724                            ) {
20725                                // always 2 digits, example 01, 02, 03
20726                                $expiryMonth = str_pad($expiryMonth, 2, '0', STR_PAD_LEFT); 
20727                                $updateTokenParams = array(
20728                                    'merchantCode' => $merchantCode,
20729                                    'paymentTokenId' => $cardToken,
20730                                    'authenticatedShopperId' => $userId,
20731                                    'xmlName' => 'update_token',
20732                                    'expiryMonth' => $expiryMonth,
20733                                    'expiryYear' => $expiryYear,
20734                                    'orderCode' => $orderCode,
20735                                    'tokenReason' => 'Payment Credit Change'
20736                                );
20737                                $ptResponseText['updateUserToken_request'][] = $updateTokenParams;
20738                                $this->log(__METHOD__ . ' New Expiry Date -> ' . $authenticatedShopperId . ' -> '. json_encode($updateTokenParams), $logFileName);
20739    
20740                                // update latest token only
20741                                $ptResponseText['updateUserToken_response'][] =  $this->updateUserToken(array(
20742                                    'updateTokenParams' => $updateTokenParams,
20743                                    'logFileName' => $logFileName,
20744                                    'dataJson' => $dataJson,
20745                                    'ptId' => $paymentTransactionData['id']
20746                                ));
20747                            }
20748
20749
20750                        } else if ($key == 0 && $formType != Configure::read('payment_credit_change')) { // NC-5642 : get the first wp token.
20751                            $cardToken = $value['tokenDetails']['paymentTokenID'];
20752                            $cardDetails = isset($value['paymentInstrument']['cardDetails']['derived']) ? $value['paymentInstrument']['cardDetails']['derived'] : array();
20753                            
20754                            // - if has no card details, check other payment instru
20755                            if (!$cardDetails) {
20756                                // - paypal
20757                                if (isset($cardInfo['paymentService']['reply']['token']['paymentInstrument']['paypal']['derived'])) {
20758                                    $cardDetails = $cardInfo['paymentService']['reply']['token']['paymentInstrument']['paypal']['derived'];
20759                                }
20760
20761                                // - emvco token
20762                                if (isset($cardInfo['paymentService']['reply']['token']['paymentInstrument']['emvcoTokenDetails']['derived'])) {
20763                                    $cardDetails = $cardInfo['paymentService']['reply']['token']['paymentInstrument']['emvcoTokenDetails']['derived'];
20764                                }
20765                                
20766                                // - sepa
20767                                if (isset($cardInfo['paymentService']['reply']['token']['paymentInstrument']['sepa']['derived'])) {
20768                                    $cardDetails = $cardInfo['paymentService']['reply']['token']['paymentInstrument']['sepa']['derived'];
20769                                }
20770                            }
20771                            $getCardDetailFlg = 1;
20772
20773                        // delete user useless token(s)
20774                        } else {
20775                            $ptResponseText['deleteUserToken_response'][] = $this->deleteUserToken(array(
20776                                'deleteTokenParams' => array(
20777                                    'merchantCode' => $merchantCode,
20778                                    'paymentTokenId' => $value['tokenDetails']['paymentTokenID'],
20779                                    'authenticatedShopperId' => $userId,
20780                                    'xmlName' => 'delete_token'
20781                                ),
20782                                'logFileName' => $logFileName,
20783                                'dataJson' => $dataJson,
20784                                'ptId' => $paymentTransactionData['id']
20785                            ));
20786                        }
20787                    }
20788                }
20789                
20790                // update payment transaction if can't generate card info and return
20791                if (!$cardToken || !$cardDetails) {
20792                    $msg = 'Failed to generate card info.';
20793                    $this->log(__METHOD__ . ' ' . $msg . ' params --> ' . json_encode($cardInfoParams) . ", error(s) --> " . json_encode($cardInfo) .' | kickback data --> ' . $dataJson, $logFileName);
20794                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' params --> ' . json_encode($cardInfoParams) . ", error(s) --> " . json_encode($cardInfo) .' | kickback data --> ' . $dataJson, 'error');
20795                    $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
20796                    throw new InternalErrorException($msg);
20797                } else {
20798                    // set card token
20799                    $saveUserArr['card_token'] = $cardToken;
20800
20801                    // set card brand
20802                    $saveUserArr['card_brand'] = $cardDetails['cardBrand'];
20803
20804                    // set card number
20805                    $saveUserArr['card_number'] = substr($cardDetails['obfuscatedPAN'], -4);
20806                }
20807            }
20808
20809            // campaign master trigger 2
20810            if (
20811                $formType == Configure::read('payment_credit_monthly_payment') && 
20812                $userData['payment_plan_id'] == Configure::read('payment_plans.free_trial')
20813            ) {
20814                UsersPointTable::giveBonusCoins(['userId' => $userId, 'triggerNo' => 2]);
20815            }
20816
20817            // update user data
20818            $uModel->clear();
20819            $uModel->recursive = -1;
20820            $read = $uModel->read(array_keys($saveUserArr), $userId);
20821            $uModel->validate = array();
20822            $uModel->set($saveUserArr);
20823            if (!$uModel->save()) {
20824                $msg = 'Updating user failed.';
20825                $this->log(__METHOD__ . ' ' . $msg . ' User data --> ' . json_encode($saveUserArr) . ' | kickback data --> ' . $dataJson, $logFileName);
20826                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' User data --> ' . json_encode($saveUserArr) . ' | kickback data --> ' . $dataJson, 'error');
20827                $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
20828                throw new InternalErrorException($msg);
20829            }
20830
20831            // check if membership status was change
20832            if (isset($ptPaymentParams['statusBefore']) && isset($ptPaymentParams['statusAfter']) && isset($ptPaymentParams['platform'])) {
20833                $currentUser = $this->User->find('first', array(
20834                    'fields' => array('User.parent_id', 'User.currency_code', 'User.payment_plan_id'),
20835                    'conditions' => array('User.id' => $userId),
20836                    'recursive' => -1
20837                ));
20838                $parentId = $currentUser['User']['parent_id'];
20839                $is_cron = 0;
20840                if (php_sapi_name() == 'cli' || $ptPaymentParams['logFileName'] == 'retry_monthly_payment'){
20841                    $is_cron = 1;
20842                } 
20843                   $currency_after = $currentUser['User']['currency_code'];
20844                   $plan_after = $currentUser['User']['payment_plan_id'];
20845                $usclData = array(
20846                    'user_id' => $userId,
20847                    'platform' => $ptPaymentParams['platform'] ?? '',
20848                    'card_company_before' => $read['User']['card_company'],
20849                    'status_before' => $ptPaymentParams['statusBefore'],
20850                    'status_after' => $ptPaymentParams['statusAfter'],
20851                    'controller_name' => $this->request->params['controller'],
20852                    'action_name' => $this->request->params['action'],
20853                    'parent_id' => $parentId,
20854                    'is_cron' => $is_cron,
20855                    'currency_before' => $currency_before,
20856                    'currency_after' => $currency_after,
20857                    'payment_plan_id_before' => $plan_before,
20858                    'payment_plan_id_after' => $plan_after,
20859                    'default_appreciation_flg' => $appreciationFlg,
20860                    'default_appreciation_amount' => $tipAmount
20861                );
20862
20863                // save user change membership status
20864                if (!$this->UserStatusChangeLog->saveLog($usclData)) {
20865                    $msg = 'Saving user status change log failed.';
20866                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' --> ' . json_encode($usclData), 'error');
20867                    $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
20868                    throw new InternalErrorException($msg);
20869                }
20870            }
20871
20872            // NC-7459 check previus user status, add coinbox challenge
20873            if (
20874                isset($userData['payment_plan_id'])
20875                && $userData['payment_plan_id'] == Configure::read('payment_plans.complimentary_plan')
20876                && isset($userData['complimentary_code'])
20877            ) {
20878
20879                // get complimentary coin award
20880                $coinAward = $this->ComplimentaryCode->find('first', array(
20881                    'fields' => array('coin_award'),
20882                    'conditions' => array(
20883                        'ComplimentaryCode.code' => $userData['complimentary_code'],
20884                        'ComplimentaryCode.template_type !=' => 0 // Free trial
20885                    )
20886                ));
20887
20888                if (
20889                    isset($coinAward['ComplimentaryCode']['coin_award'])
20890                    && $coinAward['ComplimentaryCode']['coin_award']
20891                ) { // @TODO use common @note did not use CoinBox->addCoinReward because it will not succeed for unknown reason.
20892                    $coinboxSet = array(
20893                        'status' => 1,
20894                        'user_id' => $userId,
20895                        'teacher_id' => null,
20896                        'coin_event_id' => Configure::read('coin_box_event.complimentary'),
20897                        'coin' => $coinAward['ComplimentaryCode']['coin_award'],
20898                        'lesson_id' => NULL,
20899                        'expiration_date' => date('Y-m-d 23:59:59', strtotime('+59 days'))
20900                    );
20901                    $this->CoinBox->create();
20902                    $this->CoinBox->set($coinboxSet);
20903                    if (!$this->CoinBox->save()) {
20904                        $msg = 'Saving user coin box failed.';
20905                        $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' coin box data --> ' . json_encode($coinboxSet), 'error');
20906                        $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
20907                        throw new InternalErrorException($msg);
20908                    }
20909                }
20910            }
20911
20912            // if parent user update children's card company
20913            if ($formType == Configure::read('payment_credit_change')) {
20914                $childList = $this->User->getChildId($userId);
20915                // check if user is parent
20916                if (!empty($childList)) {
20917                    foreach ($childList as $childId) {
20918                        $this->User->clear();
20919                        $updateCCArr = array('card_company' => $cardCompany);
20920                        if (!$this->User->read(array_keys($updateCCArr), $childId)) {
20921                            $this->log(__METHOD__ . ' child id does not exist.  --> ' . json_encode($updateCCArr) . ' | parent id --> ' . $userId . ' | wp data --> ' . json_encode($ptPaymentParams), $logFileName);
20922                            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - child id does not exist.  --> ' . json_encode($updateCCArr) . ' | parent id --> ' . $userId . ' | wp data --> ' . json_encode($ptPaymentParams), 'error');
20923                            return ;
20924                        }
20925
20926                        $this->User->set($updateCCArr);
20927                        if (!$this->User->save()) {
20928                            $this->log(__METHOD__ . ' failed to update child card company.   --> ' . json_encode($updateCCArr) . ' | parent id --> ' . $userId . ' | wp data --> ' . json_encode($ptPaymentParams), $logFileName);
20929                            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - failed to update child card company.   --> ' . json_encode($updateCCArr) . ' | parent id --> ' . $userId . ' | wp data --> ' . json_encode($ptPaymentParams), 'error');
20930                            return ;
20931                        }
20932                    }
20933                }
20934            }
20935
20936            $memKey = 'family_reactivation_' . $parentId . '_' . $familyId;
20937            $familyReactivation = $this->memcache->get($memKey);
20938
20939            // NC-3754 : add memo for reactivation parent user.
20940            if ($formType == Configure::read('payment_credit_family_monthly_payment') && !empty($userData['parent_id']) && $familyReactivation) {
20941                $famRegist = false;
20942                // delete memcache
20943                $this->memcache->delete($memKey);
20944                $this->User->clear();
20945                if (!$userRead = $this->User->read(array('memo'), $parentId)) {
20946                    $msg = 'User id does not exist';
20947                    $this->log(__METHOD__ . ' User id does not exist. ' . json_encode($ptPaymentParams), $logFileName);
20948                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - User id does not exist. ' . json_encode($ptPaymentParams), 'error');
20949                    $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
20950                    return ;
20951                }
20952
20953                $this->User->set(array('memo' => date('Y/m/d H:i:s')." Family plan[User]: family id: " . $userData['id'] . " reactivation \n" . $userRead['User']['memo']));
20954                $this->User->validate = false;
20955                if (!$this->User->save()) {
20956                    $msg = 'User id does not exist';
20957                    $this->log(__METHOD__ . ' Failed update user data. ' . json_encode($userRead) . ' -- ' . json_encode($ptPaymentParams), $logFileName);
20958                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed update user data. ' . json_encode($userRead) . ' -- ' . json_encode($ptPaymentParams), 'error');
20959                    $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
20960                    return ;
20961                }
20962            }
20963            
20964            // Proccess Family Plan
20965            if($famRegist && !$familyReactivation) {
20966                // @param:  parent id. for memcache key.
20967                $famPlanRes = $this->FamilyPlanList->processFamPlan($parentId, $familyId, $orderCode);
20968                if ($famPlanRes != "[OK]") {
20969                    $msg = 'Failed processing family plan.';
20970                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' - parentId --> ' . json_encode($parentId) . ' - familyId --> ' . json_encode($familyId) . ' - orderCode --> ' . json_encode($orderCode), 'error');
20971                    $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
20972                    return;
20973                }
20974            }
20975            
20976            // check if user's status is temporary
20977            if (
20978                $userData['status'] == 0 && 
20979                (
20980                    $formType == Configure::read('payment_credit_authentication') || 
20981                    $formType == Configure::read('payment_credit_family_monthly_payment') || 
20982                    $formType == Configure::read('payment_credit_family_free')
20983                )
20984            ) {
20985                // update user's status after step 4
20986                $uModel->clear();
20987                $uModel->read(array('status'), $userId);
20988                $uModel->validate = array();
20989                $uModel->set('status', 1);
20990                if (!$uModel->save()) {
20991                    $msg = 'Failed to update user status into 1.';
20992                    $this->log(__METHOD__ . ' ' . $msg . ' User id --> ' . json_encode($userId) . ' | kickback data --> ' . $dataJson, $logFileName);
20993                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' User id --> ' . json_encode($userId) . ' | kickback data --> ' . $dataJson, 'error');
20994                    $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
20995                    throw new InternalErrorException($msg);
20996                }
20997            }
20998            
20999            // NC-7779 : check if user has chivox monthly test taken for the current month, and monthly_speaking_attended_flg ON,
21000            // turn Off the flag if users has not yet taken the exam for the current month.
21001            if (
21002                isset($userData['monthly_speaking_attended_flg']) && isset($userData['monthly_speaking_business_attended_flg'])
21003                && ($userData['monthly_speaking_attended_flg'] == 1 || $userData['monthly_speaking_business_attended_flg'] == 1)
21004            ) {
21005                // check chivox monthly
21006                $paymentPlanIdsForChivoxMonthly = Configure::read('chivox.monthly.user_payment_plan_cantake_exam');
21007                if (in_array($paymentPlanId, $paymentPlanIdsForChivoxMonthly)) {
21008
21009                    // load model
21010                    $this->loadModel("UsersChivoxMonthlyTest");
21011                    $userTestMonthFlagParams['user_id'] = $userId;
21012                    $userTestMonthFlag = $this->UsersChivoxMonthlyTest->checkUserCurrentMonthExam($userTestMonthFlagParams);
21013
21014                    $monthly_speaking_attended_flg = Configure::read('chivox.test_data_test_type.daily'); // test_type daily speaking 0
21015                    $monthly_speaking_business_attended_flg = Configure::read('chivox.test_data_test_type.business'); // test_type business 1
21016                    $fieldsToUpdate = array();
21017
21018                    // if user hat not yet taken the exam for current month
21019                    if (!in_array($monthly_speaking_attended_flg, $userTestMonthFlag)) {
21020                        $fieldsToUpdate['monthly_speaking_attended_flg'] = 0;
21021                    }
21022                    if (!in_array($monthly_speaking_business_attended_flg, $userTestMonthFlag)) {
21023                        $fieldsToUpdate['monthly_speaking_business_attended_flg'] = 0;
21024                    }
21025
21026                    if ($fieldsToUpdate) {
21027                        $uModel->clear();
21028                        $uModel->recursive = -1;
21029                        $uModel->read(array_keys($fieldsToUpdate), $userId);
21030                        $uModel->validate = array();
21031                        $uModel->set($fieldsToUpdate);
21032                        if (!$uModel->save()) {
21033                            $msg = 'Failed to update user monthly_speaking_attended_flg into 0.';
21034                            $this->log(__METHOD__ . ' ' . $msg . ' User id --> ' . json_encode($userId) . ' | kickback data --> ' . $dataJson, $logFileName);
21035                            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' User id --> ' . json_encode($userId) . ' | kickback data --> ' . $dataJson, 'error');
21036                            $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
21037                            throw new InternalErrorException($msg);
21038                        }
21039                    }
21040                }
21041            }
21042        }
21043
21044        // if purchase coin
21045        if ($formType == Configure::read('payment_credit_coin_purchase') && isset($ptPaymentParams['coinPurchasePoints'])) {
21046            // change user id to child id
21047            if($familyId){
21048                $pointParamsUserId = $familyId;
21049            }else{
21050                $pointParamsUserId = $userId;
21051            }
21052
21053            $coinPurchasePoints = intVal($ptPaymentParams['coinPurchasePoints']);
21054            $coinData = $this->UsersPoint->SET_charge_overseas_menue($coinPurchasePoints, $currencyCode);
21055            
21056            // NC-5007 add to the user's existing coin
21057            $pcWorldPay = array(
21058                'userId' => $pointParamsUserId,
21059                'point' => $coinData['num_of_coin'] - $coinData['bonus_coin'],
21060                'kbn' => 7,
21061                'kbnType' => 1, // add coin
21062                'coinType' => 1, // purchase coin
21063                'coinFailMessage' => Configure::read('coin.failed.buy_coin'),
21064                'device' => isset($ptPaymentParams['device']) ? $ptPaymentParams['device'] : null
21065            );
21066
21067            $scWorldPay = array(
21068                'userId' => $pointParamsUserId,
21069                'point' => $coinData['bonus_coin'],
21070                'kbn' => 7,
21071                'kbnType' => 1, // add coin
21072                'coinType' => 2, // service coin
21073                'coinFailMessage' => Configure::read('coin.failed.buy_coin'),
21074                'device' => isset($ptPaymentParams['device']) ? $ptPaymentParams['device'] : null
21075            );
21076
21077            $pointParams = [$pcWorldPay, $scWorldPay];
21078
21079            if ( $pointParams ) {
21080                foreach($pointParams as $key => $val) {
21081                    if (!$this->UsersPoint->performPointTransaction($val)) {
21082                        $msg = 'Adding user coin history failed.';
21083                        $this->log(__METHOD__ . ' ' . $msg . json_encode($val) . ' -- ' . $dataJson, $logFileName);
21084                        $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . json_encode($val) . ' -- ' . $dataJson, 'error');
21085                        $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
21086                        throw new InternalErrorException($msg);
21087                    }
21088                }
21089            }
21090        }
21091
21092        // [WorldPay] check if receivable payment sent was either
21093        // receivable payment, monthly payment, force settlement, or retry payment or payment change
21094        // if yes, set receivable payments to "received"
21095        if (
21096            in_array($formType, array(
21097                Configure::read('payment_credit_appreciation_receivable'),
21098                Configure::read('payment_credit_receivable'),
21099                Configure::read('payment_credit_monthly_payment'),
21100                Configure::read('payment_credit_force_charge'),
21101                Configure::read('payment_credit_retry'),
21102                Configure::read('payment_credit_family_monthly_payment')
21103            )) ||
21104            (
21105                $formType == Configure::read('payment_credit_change') &&
21106                (
21107                    $receivablePayment ||
21108                    $appreciationReceivable ||
21109                    $liveLessonReceivable
21110                )
21111            )
21112        ) {
21113            // create new payment receivable
21114            if ($formType != Configure::read('payment_credit_receivable') && $receivablePayment) {
21115                // set payment id
21116                $data["payment_id"] = $paymentId;
21117
21118                // set variables
21119                $paymentData = array(
21120                    'user_id' => $userId,
21121                    'type_id' => $typeId,
21122                    'reference_id' => $userId,
21123                    'status' => $paymentStatus,
21124                    'form_type' => Configure::read('payment_credit_receivable'),
21125                    'ordd' => $orderCode,
21126                    'amount' => $receivablePayment,
21127                    'param1' => $dataJson,
21128                    'card_company' => $cardCompany,
21129                    'transaction_code' => $orderCode,
21130                    'currency_code' => $currencyCode,
21131                    'payment_id' => $paymentPlanId,
21132                    'price_id' => $priceId,
21133                    'payment_type' => $paymentType,
21134                    'discounted_amount' => 0
21135                );
21136
21137                // create new payment
21138                $pModel->clear();
21139                $pModel->create();
21140                $pModel->validate = array();
21141                $pModel->set($paymentData);
21142
21143                if (!$pModel->save()) {
21144                    $msg = 'Saving payment receivable failed.';
21145                    $this->log(__METHOD__ . ' ' . $msg . ' Params --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, $logFileName);
21146                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' - new payment receivable - Params --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, 'error');
21147                    $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
21148                    throw new InternalErrorException($msg);
21149                }
21150                //update/add user`s settlement amount
21151                $this->User->updateUserPayments($paymentData);
21152                // set payment_id
21153                $paymentId = $pModel->id;
21154
21155            }
21156
21157            // set payment receivable statuses to 2 - received
21158            $this->PaymentReceivable->updateReceivableReservationPayment(
21159                $userId, 
21160                array(
21161                    'status' => 2,
21162                    'payment_id' => $paymentId,
21163                    'payment_collection_date' => $dateNow,
21164                    'card_company' => $cardCompany,
21165                    'payment_plan_id' => $paymentPlanId,
21166                    'membership_type_index' => $membershipStatusIndex
21167                ),
21168                array(
21169                    'PaymentReceivable.user_id' => $userId,
21170                    'PaymentReceivable.status' => 0,
21171                    'PaymentReceivable.payment_element_type' => 1,
21172                    'PaymentReceivable.created <=' => $cronDateRun
21173                )
21174            );
21175
21176            // create new appreciation lesson payment receivable
21177            if ($formType != Configure::read('payment_credit_appreciation_receivable') && $appreciationReceivable > 0) {
21178                // set payment id
21179                $data["payment_id"] = $paymentId;
21180                //reset payment data
21181                $paymentData = array();
21182
21183                // set variables
21184                $paymentData = array(
21185                    'user_id' => $userId,
21186                    'type_id' => $typeId,
21187                    'reference_id' => $userId,
21188                    'status' => $paymentStatus,
21189                    'form_type' => Configure::read('appreciation_data.payment_form_type'),
21190                    'ordd' => $orderCode,
21191                    'amount' => $appreciationReceivable,
21192                    'param1' => $dataJson,
21193                    'card_company' => $cardCompany,
21194                    'transaction_code' => $orderCode,
21195                    'currency_code' => $currencyCode,
21196                    'payment_id' => $paymentPlanId,
21197                    'price_id' => $priceId,
21198                    'payment_type' => $paymentType,
21199                    'discounted_amount' => 0
21200                );
21201
21202                // create new payment
21203                $pModel->clear();
21204                $pModel->create();
21205                $pModel->validate = array();
21206                $pModel->set($paymentData);
21207
21208                if (!$pModel->save()) {
21209                    $msg = 'Saving appreciation payment receivable failed.';
21210                    $this->log(__METHOD__ . ' ' . $msg . ' Params --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, $logFileName);
21211                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' Params --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, 'error');
21212                    $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
21213                    throw new InternalErrorException($msg);
21214                }
21215                //update/add user`s settlement amount
21216                $this->User->updateUserPayments($paymentData);
21217                // set payment_id
21218                $paymentId = $pModel->id;
21219    
21220            }
21221
21222            // set payment receivable statuses to 2 - received
21223            $this->PaymentReceivable->updateReceivableReservationPayment(
21224                $userId, 
21225                array(
21226                    'status' => 2,
21227                    'payment_id' => $paymentId,
21228                    'payment_collection_date' => $dateNow,
21229                    'card_company' => $cardCompany,
21230                    'payment_plan_id' => $paymentPlanId,
21231                    'membership_type_index' => $membershipStatusIndex
21232                ),
21233                array(
21234                    'PaymentReceivable.user_id' => $userId,
21235                    'PaymentReceivable.status' => 0,
21236                    'PaymentReceivable.payment_element_type' => Configure::read('appreciation_data.payment_element_type'),
21237                    'PaymentReceivable.created <=' => $cronDateRun
21238                )
21239            );
21240
21241            // create new live lesson payment receivable
21242            if ($formType != Configure::read('payment_live_lesson_receivable') && $liveLessonReceivable) {
21243                // set payment id
21244                $data["payment_id"] = $paymentId;
21245
21246                // set variables
21247                $paymentData = array(
21248                    'user_id' => $userId,
21249                    'type_id' => $typeId,
21250                    'reference_id' => $userId,
21251                    'status' => $paymentStatus,
21252                    'form_type' => Configure::read('payment_live_lesson_receivable'),
21253                    'ordd' => $orderCode,
21254                    'amount' => $liveLessonReceivable,
21255                    'param1' => $dataJson,
21256                    'card_company' => $cardCompany,
21257                    'transaction_code' => $orderCode,
21258                    'currency_code' => $currencyCode,
21259                    'payment_id' => $paymentPlanId,
21260                    'price_id' => $priceId,
21261                    'payment_type' => $paymentType,
21262                    'discounted_amount' => 0
21263                );
21264
21265                // create new payment
21266                $pModel->clear();
21267                $pModel->create();
21268                $pModel->validate = array();
21269                $pModel->set($paymentData);
21270
21271                if (!$pModel->save()) {
21272                    $msg = 'Saving payment receivable failed.';
21273                    $this->log(__METHOD__ . ' ' . $msg . ' Params --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, $logFileName);
21274                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' - new live lesson payment receivable - Params --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, 'error');
21275                    $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
21276                    throw new InternalErrorException($msg);
21277                }
21278                //update/add user`s settlement amount
21279                $this->User->updateUserPayments($paymentData);
21280                // set payment_id
21281                $paymentId = $pModel->id;
21282            }
21283
21284            // set payment receivable statuses to 2 - received
21285            $this->PaymentReceivable->updateReceivableReservationPayment(
21286                $userId, 
21287                array(
21288                    'status' => 2,
21289                    'payment_id' => $paymentId,
21290                    'payment_collection_date' => $dateNow,
21291                    'card_company' => $cardCompany,
21292                    'payment_plan_id' => $paymentPlanId,
21293                    'membership_type_index' => $membershipStatusIndex
21294                ),
21295                array(
21296                    'PaymentReceivable.user_id' => $userId,
21297                    'PaymentReceivable.status' => 0,
21298                    'PaymentReceivable.payment_element_type' => Configure::read('payment_element_type.live'),
21299                    'PaymentReceivable.created <=' => $cronDateRun
21300                )
21301            );    
21302        }
21303
21304
21305        // NC-7029: CHECK REFERRAL USER
21306        if (
21307            in_array($formType, array(
21308                Configure::read('payment_credit_monthly_payment'),
21309                Configure::read('payment_credit_force_charge'),
21310                Configure::read('payment_credit_retry'),
21311                Configure::read('payment_credit_authentication')
21312            ))
21313        ) {
21314            $ruData = array(
21315                'referee_id' => $userId,
21316                'payment_plan_id' => $paymentPlanId,
21317                'currency_code' => $userData['currency_code'],
21318                'logFileName' => $logFileName,
21319                'form_type' => $formType
21320            );
21321
21322            $couponReferredData = $this->UsersReferral->checkReferredUser($ruData);
21323            if (isset($couponReferredData['error']) && $couponReferredData['error']) {
21324                $msg = 'Failed to update users referral event flg.';
21325                $this->log(__METHOD__ . ' ' . $msg . ' Params --> ' . json_encode($ruData) . ' | kickback data --> ' . $dataJson, $logFileName);
21326                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' Params --> ' . json_encode($ruData) . ' | kickback data --> ' . $dataJson, 'error');
21327                $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
21328                throw new InternalErrorException($msg);
21329            }
21330
21331            $couponMailId = Configure::read('site_in_mail.coupon_mail_template_id');
21332
21333            // send coupon mail to referee
21334            if (isset($couponReferredData['sendMailToReferee']) && $couponReferredData['sendMailToReferee']) {
21335                $refereeData = array(
21336                    'id' => $userData['id'],
21337                    'email' => $userData['email'],
21338                    'native_language2' => $userData['native_language2'],
21339                    'hash' => $userData['hash'],
21340                    'refereeName' => $userData['nickname'],
21341                    'referrerName' => $couponReferredData['referrerName'],
21342                    'couponAmount' => $couponReferredData['refereeSaveAmount'],
21343                    'couponUpdatedTotal' => $couponReferredData['refereeUpdatedTotal']
21344                );
21345
21346                // send mail to referee
21347                myMailer::sendTemplateMail($couponMailId, $userData['email'], $refereeData, array(), 'User');
21348            }
21349
21350            // send coupon mail to referer
21351            if (isset($couponReferredData['sendMailToReferer']) && $couponReferredData['sendMailToReferer']) {
21352                $referrerData = array(
21353                    'id' => $couponReferredData['referrerId'],
21354                    'email' => $couponReferredData['referrerEmail'],
21355                    'native_language2' => $couponReferredData['nativeLanguage2'],
21356                    'hash' => $couponReferredData['referrerHash'],
21357                    'refereeName' => $userData['nickname'],
21358                    'referrerName' => $couponReferredData['referrerName'],
21359                    'couponAmount' => $couponReferredData['refererSaveAmount'],
21360                    'couponUpdatedTotal' => $couponReferredData['refererUpdatedTotal']
21361                );
21362
21363                // send mail to referrer
21364                myMailer::sendTemplateMail($couponMailId, $couponReferredData['referrerEmail'], $referrerData, array(), 'User');
21365            }
21366
21367            // NJ-47740
21368            if (!empty($ptPaymentParams['monthlyDiscount']) && !empty($ptPaymentParams['monthly_grp_id'])) {
21369                $requestCouponConfirmData = array(
21370                    'grpId' => $ptPaymentParams['monthly_grp_id'],
21371                    'paymentId' => $paymentSaveID
21372                );
21373                
21374                $result_confirm = $this->UsersCouponV1->performCouponConfirm($requestCouponConfirmData);
21375                    
21376                if (!$result_confirm) {
21377                    $msg = 'Failed to confirm coupon use request.';
21378                    $this->log(__METHOD__ . ' Failed to confirm coupon use request. ' . json_encode($requestCouponConfirmData) . ' -- ' . $dataJson, $logFileName);
21379                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' ' . json_encode($requestCouponConfirmData) . ' -- ' . $dataJson, 'error');
21380                    $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
21381                }
21382            }
21383            
21384            //update/add user`s settlement amount
21385            if(!$this->User->updateUserPayments($paymentData)) {
21386                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to update user payments - REFERRAL USER --> ' . json_encode($paymentData), 'error');
21387            }
21388        } 
21389
21390        // if has native speaker payment
21391        // NJ-47740
21392        $getCouponDiscounDetail = PaymentTable::getCouponDiscountRequestDetail($ptPaymentParams, 'native');
21393        $nativeOptionDiscount = !empty($getCouponDiscounDetail['discounted_amount']) ? $getCouponDiscounDetail['discounted_amount'] : 0;
21394        $nativeCouponRequestId = !empty($getCouponDiscounDetail['coupon_request_id']) ? $getCouponDiscounDetail['coupon_request_id'] : null;
21395        if (
21396            isset($ptPaymentParams['nativeOptionPayment']) && ($ptPaymentParams['nativeOptionPayment'] > 0 || $nativeOptionDiscount > 0)
21397            && in_array($ptPaymentParams['formType'], array(Configure::read('payment_credit_monthly_payment'), Configure::read('payment_credit_family_monthly_payment')))
21398        ) {
21399            if(isset($ptPaymentParams['nativeOptionJoin']) && $ptPaymentParams['nativeOptionJoin']) {
21400                $nspFormType = Configure::read('payment_native_option_join');
21401            } else {
21402                $nspFormType = Configure::read('payment_native_option_monthly_payment');
21403            }
21404
21405            // check if family plan
21406            if ($familyId && $parentId) {
21407                // change reference id to parent id
21408                $referenceId = $parentId;
21409            } else {
21410                $referenceId = $userId;
21411            }
21412
21413            $paymentData = array(
21414                'user_id' => $userId,
21415                'type_id' => $typeId,
21416                'reference_id' => $referenceId,
21417                'payment_transaction_password' => $ptPassword,
21418                'status' => $paymentStatus,
21419                'form_type' => $nspFormType,
21420                'ordd' => $orderCode,
21421                'amount' => $ptPaymentParams['nativeOptionPayment'],
21422                'param1' => $dataJson,
21423                'card_company' => $cardCompany,
21424                'transaction_code' => $orderCode,
21425                'currency_code' => $currencyCode,
21426                'payment_id' => $paymentPlanId,
21427                'price_id' => $priceId,
21428                'payment_type' => Configure::read('payment_types.native_option'),
21429            );
21430            
21431            // NJ-47740
21432            $paymentData['discounted_amount'] = $nativeOptionDiscount;
21433            $paymentData['coupon_request_id'] = $nativeCouponRequestId;
21434
21435            // create new payment
21436            $pModel->clear();
21437            $pModel->create();
21438            $pModel->validate = array();
21439            $pModel->set($paymentData);
21440
21441            if (!$pModel->save()) {
21442                $msg = 'Saving payment receivable failed.';
21443                $this->log(__METHOD__ . ' ' . $msg . ' Params --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, $logFileName);
21444                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' - native speaker payment - Params --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, 'error');
21445                $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
21446                throw new InternalErrorException($msg);
21447            }
21448
21449            //update/add user`s settlement amount
21450            if(!$this->User->updateUserPayments($paymentData)) {
21451                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to update user payments - if has native speaker payment --> ' . json_encode($paymentData), 'error');
21452            }
21453            
21454            // NJ-47740
21455            if (!empty($paymentData['coupon_request_id']) && $paymentData['discounted_amount'] > 0) {
21456                // confirm coupon use request for native discount
21457                $requestCouponConfirmData = array(
21458                    'grpId' => $paymentData['coupon_request_id'],
21459                    'paymentId' => $pModel->id
21460                );
21461                $result_confirm = $this->UsersCouponV1->performCouponConfirm($requestCouponConfirmData);
21462                
21463                if (!$result_confirm) {
21464                    $msg = 'Failed to confirm native coupon use request.';
21465                    $this->log(__METHOD__ . ' Failed to confirm native coupon use request. ' . json_encode($requestCouponConfirmData) . ' -- ' . $dataJson, $logFileName);
21466                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to confirm native coupon use request. ' . json_encode($requestCouponConfirmData) . ' -- ' . $dataJson, 'error');
21467                    $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
21468                    throw new InternalErrorException($msg);
21469                }
21470            }
21471            // NJ-47740 end
21472            
21473            // update payment details
21474            $updatePaymentDetailParams = array(
21475                'currencyCode' => $paymentData['currency_code'],
21476                'formType' => $paymentData['form_type'],
21477                'paymentType' => $paymentData['payment_type'],
21478                'amount' => $paymentData['amount'],
21479                'discounted_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0,
21480                'familyId' => $familyId,
21481                'cronDateRun' => $cronDateRun,
21482                'priceId' => $paymentData['price_id'],
21483                'paymentPlanId' => $paymentData['payment_id'],
21484                'user_id' => $paymentData['user_id'],
21485                'coupon_use_request_id' => isset($paymentData['coupon_request_id']) ? $paymentData['coupon_request_id'] : null,
21486                'coupon_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0
21487            );
21488
21489            $updatePaymentDetail = array(
21490                'id' => $paymentTransactionData['id'],
21491                'fields' => array(
21492                    'payment_details' => $updatePaymentDetailParams
21493                )
21494            );
21495
21496            if (!$this->PaymentTransaction->updateWPPaymentTransaction($updatePaymentDetail)) {
21497                $this->log(__METHOD__ . ' Failed to update payment details. ' . json_encode($updatePaymentDetail), $logFileName);
21498                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to update payment details - if has native speaker payment ' . json_encode($updatePaymentDetail), 'error');
21499            }
21500        }
21501
21502        // if has callan option payment
21503        $getCouponDiscounDetail = PaymentTable::getCouponDiscountRequestDetail($ptPaymentParams, 'callan');
21504        $callanOptionDiscount = !empty($getCouponDiscounDetail['discounted_amount']) ? $getCouponDiscounDetail['discounted_amount'] : 0;
21505        $callanCouponRequestId = !empty($getCouponDiscounDetail['coupon_request_id']) ? $getCouponDiscounDetail['coupon_request_id'] : null;
21506        if (
21507            isset($ptPaymentParams['callanOptionPayment']) && ($ptPaymentParams['callanOptionPayment'] > 0 || $callanOptionDiscount > 0)
21508            && in_array($ptPaymentParams['formType'], array(Configure::read('payment_credit_monthly_payment'), Configure::read('payment_credit_family_monthly_payment')))
21509        ) {
21510            
21511            $nspFormType = Configure::read('payment_callan_option_monthly_payment');
21512            if(isset($ptPaymentParams['callanOptionJoin']) && $ptPaymentParams['callanOptionJoin']) {
21513                $nspFormType = Configure::read('payment_callan_option_join');
21514            }
21515
21516            // check if family plan
21517            if ($familyId && $parentId) {
21518                // change reference id to parent id
21519                $referenceId = $parentId;
21520            } else {
21521                $referenceId = $userId;
21522            }
21523
21524            $paymentData = array(
21525                'user_id' => $userId,
21526                'type_id' => $typeId,
21527                'reference_id' => $referenceId,
21528                'payment_transaction_password' => $ptPassword,
21529                'status' => $paymentStatus,
21530                'form_type' => $nspFormType,
21531                'ordd' => $orderCode,
21532                'amount' => $ptPaymentParams['callanOptionPayment'],
21533                'param1' => $dataJson,
21534                'card_company' => $cardCompany,
21535                'transaction_code' => $orderCode,
21536                'currency_code' => $currencyCode,
21537                'payment_id' => $paymentPlanId,
21538                'price_id' => $priceId,
21539                'payment_type' => Configure::read('payment_types.callan_option'),
21540            );
21541            
21542            // NJ-47740
21543            $paymentData['discounted_amount'] = $callanOptionDiscount;
21544            $paymentData['coupon_request_id'] = $callanCouponRequestId;
21545
21546            // create new payment
21547            $pModel->clear();
21548            $pModel->create();
21549            $pModel->validate = array();
21550            $pModel->set($paymentData);
21551
21552            if (!$pModel->save()) {
21553                $msg = 'Saving payment receivable failed.';
21554                $this->log(__METHOD__ . ' ' . $msg . ' Params --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, $logFileName);
21555                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' - callan option payment - Params --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, 'error');
21556                $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
21557                throw new InternalErrorException($msg);
21558            }
21559
21560            //update/add user`s settlement amount
21561            $this->User->updateUserPayments($paymentData);
21562            
21563            // NJ-47740
21564            if (!empty($paymentData['coupon_request_id']) && $paymentData['discounted_amount'] > 0) {
21565                // confirm coupon use request for callan discount
21566                $requestCouponConfirmData = array(
21567                    'grpId' => $paymentData['coupon_request_id'],
21568                    'paymentId' => $pModel->id
21569                );
21570                $result_confirm = $this->UsersCouponV1->performCouponConfirm($requestCouponConfirmData);
21571                
21572                if (!$result_confirm) {
21573                    $msg = 'Failed to confirm callan coupon use request.';
21574                    $this->log(__METHOD__ . ' Failed to confirm callan coupon use request. ' . json_encode($requestCouponConfirmData) . ' -- ' . $dataJson, $logFileName);
21575                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to confirm callan coupon use request. ' . json_encode($requestCouponConfirmData) . ' -- ' . $dataJson, 'error');
21576                    $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
21577                    throw new InternalErrorException($msg);
21578                }
21579            }
21580            // NJ-47740 end
21581            
21582            // update payment details
21583            $updatePaymentDetailParams = array(
21584                'currencyCode' => $paymentData['currency_code'],
21585                'formType' => $paymentData['form_type'],
21586                'paymentType' => $paymentData['payment_type'],
21587                'amount' => $paymentData['amount'],
21588                'discounted_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0,
21589                'familyId' => $familyId,
21590                'cronDateRun' => $cronDateRun,
21591                'priceId' => $paymentData['price_id'],
21592                'paymentPlanId' => $paymentData['payment_id'],
21593                'user_id' => $paymentData['user_id'],
21594                'coupon_use_request_id' => isset($paymentData['coupon_request_id']) ? $paymentData['coupon_request_id'] : null,
21595                'coupon_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0
21596            );
21597
21598            $updatePaymentDetail = array(
21599                'id' => $paymentTransactionData['id'],
21600                'fields' => array(
21601                    'payment_details' => $updatePaymentDetailParams
21602                )
21603            );
21604
21605            if (!$this->PaymentTransaction->updateWPPaymentTransaction($updatePaymentDetail)) {
21606                $this->log(__METHOD__ . ' Failed to update payment details. ' . json_encode($updatePaymentDetail), $logFileName);
21607                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to update payment details. - if has callan option payment' . json_encode($updatePaymentDetail), 'error');
21608            }
21609        }
21610        
21611        // activate the user native option (new, resume, and monthly payment)
21612        if (isset($ptPaymentParams['nativeOptionPayment']) && ($ptPaymentParams['nativeOptionPayment'] > 0 || $nativenOptionDiscount > 0)) { 
21613            $this->log(__METHOD__ . ' NJ-2388 debug Payment Transaction Data: ' . json_encode($paymentTransactionData), 'native_option_debug');
21614            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - NJ-2388 debug Payment Transaction Data: ' . json_encode($paymentTransactionData), 'error');
21615
21616            // - option process data
21617            $optionProcessData = array(
21618                'user_id' => $userId,
21619                'type' => 'on',
21620                'option_type' => Configure::read('native_speaker.options.all_you_can_eat')
21621            );
21622            
21623            if(!$this->User->userNativeOptionProcess($optionProcessData)) {
21624                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Fail process on userNativeOptionProcess - nativeOptionPayment - data --> ' . json_encode($optionProcessData), 'error');
21625            }
21626
21627            //NJ-2814 add logs
21628            if (isset($ptPaymentParams['nativeOptionJoin']) && $ptPaymentParams['nativeOptionJoin']) {
21629                $nativeStatus = 1; // subscribed
21630                $statusBefore = '';
21631            } else {
21632                $nativeStatus = 2; // Monthly Continue
21633                $statusBefore = 1;
21634            }
21635
21636            $optionAfterName = 'Native Unlimited Option';
21637
21638            $optionLogParams = array(
21639                'user_id' => $userId,
21640                'platform' => $ptPaymentParams['platform'],
21641                'status' => $nativeStatus,
21642                'controller_name' => $this->request->params['controller'],
21643                'action_name' => $this->request->params['action'],
21644                'user_type' => 0, // user
21645                'option_before' => $statusBefore,
21646                'option_after' => 1,
21647                'option_before_name' => '',
21648                'option_after_name' => $optionAfterName,
21649                'option_type' => 1,
21650                'payment_plan_id' => $paymentPlanId
21651            );
21652
21653            if(!ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams)) {
21654                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed saving in saveOptionChangeLog - nativeOptionPayment - data --> ' . json_encode($optionLogParams), 'error');
21655            }
21656
21657            // - save registration status step
21658            $stepKey = Configure::read('registration_steps.user_info_entry');
21659            $this->saveStep($userId, $stepKey);
21660
21661        }
21662
21663        // activate the user native option (new, resume, and monthly payment)
21664        if (isset($ptPaymentParams['callanOptionPayment']) && ($ptPaymentParams['callanOptionPayment'] > 0 || $callanOptionDiscount > 0)) { 
21665            $this->log(__METHOD__ . ' NJ-2388 debug Payment Transaction Data: ' . json_encode($paymentTransactionData), 'native_option_debug');
21666
21667            // - option process data
21668            $optionProcessData = array(
21669                'user_id' => $userId,
21670                'type' => 'on',
21671                'option_type' => Configure::read('callan_unlimited.options.callan_unlimited_option')
21672            );
21673            if(!$this->User->userNativeOptionProcess($optionProcessData)) {
21674                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Fail process on userNativeOptionProcess - callanOptionPayment - data --> ' . json_encode($optionProcessData), 'error');
21675            }
21676
21677            //NJ-2814 add logs
21678            if (isset($ptPaymentParams['callanOptionJoin']) && $ptPaymentParams['callanOptionJoin']) {
21679                $callanStatus = 1; // subscribed
21680                $statusBefore = '';
21681            } else {
21682                $callanStatus = 2; // Monthly Continue
21683                $statusBefore = 1;
21684            }
21685
21686            $optionAfterName = 'Callan Unlimited Option';
21687
21688            $optionLogParams = array(
21689                'user_id' => $userId,
21690                'platform' => $ptPaymentParams['platform'],
21691                'status' => $callanStatus,
21692                'controller_name' => $this->request->params['controller'],
21693                'action_name' => $this->request->params['action'],
21694                'user_type' => 0, // user
21695                'option_before' => $statusBefore,
21696                'option_after' => 1,
21697                'option_before_name' => '',
21698                'option_after_name' => $optionAfterName,
21699                'option_type' => 2,
21700                'payment_plan_id' => $paymentPlanId
21701            );
21702
21703            if(!ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams)) {
21704                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed saving in saveOptionChangeLog - callanOptionPayment - data --> ' . json_encode($optionLogParams), 'error');
21705            }
21706        }
21707
21708        // update payment transaction payment id, status and response text
21709        $ptUpdate = $this->updatePaymentTransaction(array(
21710            'id' => $paymentTransactionData['id'],
21711            'fields' => array(
21712                'status' => 1, // done
21713                'payment_id' => $paymentId,
21714                'response_text' => $ptResponseText
21715            ),
21716            'logFileName' => $logFileName
21717        ));
21718
21719        if (!$ptUpdate) {
21720            $msg = 'Updating payment transaction failed.';
21721            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg, 'error');
21722            $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
21723            throw new InternalErrorException($msg);
21724        }
21725
21726        // final save
21727
21728        // add registration bonus if user registration
21729        if (isset($ptPaymentParams['userRegister']) && $ptPaymentParams['userRegister']) {
21730
21731            UsersPointHistoryTable::checkDailyBonus($userId);
21732            $params = array(
21733                "type" => 1, // kickback
21734                "userID" => $userId,
21735                "userRegister" => true
21736            );
21737
21738            // add referral coin NC-9359
21739            $this->User->addReferralBonus($params);
21740
21741            // - get bonus coins on registration
21742            $receiveBonus = UsersPointTable::checkIfUserReceiveBonusUponRegister($userId);
21743            
21744            if (!$receiveBonus && empty($userData['complimentary_code'])) {
21745                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - giveBonusCoins triggered', 'error');
21746                UsersPointTable::giveBonusCoins(['userId' => $userId, 'triggerNo' => 1]);
21747            }
21748        }
21749
21750        // campaign master trigger 5
21751        $this->retrial_confiscate_coins([
21752            'formType' => $formType,
21753            'paymentPlanId' => $paymentPlanId,
21754            'userId' => $userId
21755        ]);
21756
21757        // send event to adjust
21758        $adjustParams = array(
21759            'formType' => $formType,
21760            'statusBefore' => isset($ptPaymentParams['statusBefore']) ? $ptPaymentParams['statusBefore'] : null,
21761            'userId' => $userId
21762        );
21763        UserTable::sendEventToAdjust($adjustParams);
21764
21765        //NJ-23626 continuing plan campaign
21766        if (in_array($formType, array(Configure::read('payment_credit_retry'), Configure::read('payment_credit_monthly_payment')))){
21767            ClassRegistry::init('CampaignSettingTable')->takingLessonAndContinuePlan(array('user_id' => $userId, 'type' => 3));
21768        }
21769
21770        // - NJ-31307 : trigger campaign
21771        ClassRegistry::init('CampaignSettingTable')->callanUnlimitedCampaign(array(
21772            'user_id' => $userId, 
21773            'trigger' => 3, 
21774            'pt_params' => $paymentTransactionData ?? [],
21775            'payment_type' => 'Worldpay'
21776        ));
21777
21778        $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - DONE WP PROCESS --> ' . json_encode($data), 'error');
21779        echo "[OK]"; exit;
21780    }
21781
21782    /**
21783     * NC-4770: get user using request token and validate
21784     * @param array $params
21785     * @return array $userData
21786     */
21787    private function mobappGetUserData($params = array()) {
21788        $urlParams = myTools::getMobappToken($_GET);
21789
21790        if (!isset($params['logFileName']) || !isset($params['formType'])) {
21791            $this->log(__METHOD__ . ' Missing parameters(s). ' . json_encode($params), $logFileName);
21792            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
21793        }
21794
21795        $logFileName = $params['logFileName'];
21796        $formType = $params['formType'];
21797
21798        // redirect to retry page is param token is not set
21799        if (!isset($this->request->query['token']) || empty($this->request->query['token'])) {
21800            
21801            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
21802        }
21803        
21804        $apiToken = $this->request->query['token']; 
21805        $userParams = array(
21806            'fields' => array(
21807                'User.id',
21808                'User.status',
21809                'User.hash16',
21810                'User.hash',
21811                'User.native_language2',
21812                'User.email',
21813                'User.charge_flg',
21814                'User.parent_id',
21815                'User.fail_flg',
21816                'User.corporate_id',
21817                'User.corporate_type',
21818                'User.first_charge_date',
21819                'User.first_lesson_time',
21820                'User.monthly_payment',
21821                'User.card_token',
21822                'User.card_brand',
21823                'User.card_number',
21824                'User.api_token',
21825                'User.currency_code',
21826                'User.payment_plan_id',
21827                'User.price_id',
21828                'User.wp_transaction_identifier',
21829                'User.complimentary_code',
21830                'User.card_company',
21831                'User.double_check_flg',
21832                'User.platform',
21833                'User.idfa',
21834                'User.monthly_speaking_attended_flg',
21835                'User.monthly_speaking_business_attended_flg',
21836                'User.paypal_payer_id',
21837                'User.birthday',
21838                'PaymentPlanPrice.amount',
21839                'User.studysapuri_id',
21840                'User.nickname',
21841                'User.aftee_transaction_identifier',
21842                'User.phone_number',
21843                'User.sms_through_flg',
21844                'User.paypal_payer_id',
21845                'User.paypal_payer_email'
21846        ),
21847            'apiToken' => $apiToken
21848        );
21849
21850        // redirect to retry page if user does not exist using param token
21851        if (!$userData = $this->User->getWPMobappUserData($userParams)) {
21852            $this->log(__METHOD__ . ' User does not exist. ' . json_encode($userParams), $logFileName);
21853            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
21854        }
21855
21856        $user = new UserTable($userData['User']);
21857        $memberType = $user->getUserMembership();
21858
21859        // redirect to error page if settlement cron is currently on-going
21860        if (UserTable::checkPayingUser($user->id)) {
21861            return $this->redirect(myTools::getUrl() . '/mobapp/retry/error'.$urlParams);
21862        }
21863
21864        // redirect to retry page if currency code is null
21865        if (!isset($user->currency_code)) {
21866            $this->log(__METHOD__ . ' User currency code is null. ' . json_encode($user), $logFileName);
21867            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
21868        }
21869
21870        // if done paying using 3D secure, skip membership type checking
21871        $zeus3DSecureChallengeFlg = $this->memcache->get('zeus3DSecureChallengeFlg_' . $user->id);
21872        if ($zeus3DSecureChallengeFlg) {
21873            if (
21874                isset($user->complimentary_code) &&
21875                (
21876                    (isset($user->payment_plan_id) && $user->payment_plan_id == Configure::read('payment_plans.complimentary_plan')) ||
21877                    (!isset($user->payment_plan_id) && $this->Payment->ifComPlanUser($user->id))
21878                )
21879            ) {
21880                $userData['User']['com_plan_user'] = true;
21881            }
21882
21883            return $userData;
21884        }
21885
21886        switch($formType) {
21887            case Configure::read('payment_credit_retry'):
21888                if ($memberType != Configure::read('user.member_type_fail')) {
21889                    $this->log(__METHOD__ . ' User is not fail. result data --> ' . json_encode($userData), $logFileName);
21890                    return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
21891                }
21892                break;
21893            case Configure::read('payment_credit_authentication'):
21894                if ($memberType != Configure::read('user.member_type_free') && !$user->complimentary_code) {
21895                    $this->log(__METHOD__ . ' User charge_flg is not 0. result data --> ' . json_encode($userData), $logFileName);
21896                    return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
21897                }
21898                break;
21899            case Configure::read('payment_credit_force_charge'):
21900                if (
21901                    isset($user->complimentary_code) &&
21902                    (
21903                        (isset($user->payment_plan_id) && $user->payment_plan_id == Configure::read('payment_plans.complimentary_plan')) ||
21904                        (!isset($user->payment_plan_id) && $this->Payment->ifComPlanUser($user->id))
21905                    )
21906                ) {
21907                    $userData['User']['com_plan_user'] = true;
21908                    break;
21909                }
21910                // corporate light
21911                $corpType = myTools::getCoporateTypeUsingPaymentPlanId($user->payment_plan_id);
21912                if ( $corpType  == Configure::read("corporate_type.light") ) {
21913                    break;
21914                }
21915
21916
21917        }
21918
21919        return $userData;
21920    }
21921
21922    private function getRetryPaymentData($userData = array(), $logFileName = 'debug') {
21923        $result = array();
21924
21925        // if empty
21926        if (empty($userData)) {
21927            $this->log(__METHOD__. ' user data is empty ->' . json_encode($userData), $logFileName);
21928            return $result;
21929        }
21930
21931        // if empty currency code
21932        if (!isset($userData['currency_code'])) {
21933            $this->log(__METHOD__. ' user currency code is empty ->' . json_encode($userData), $logFileName);
21934            return $result;
21935        }
21936
21937        // if empty payment plan id
21938        if (!isset($userData['payment_plan_id'])) {
21939            $this->log(__METHOD__. ' user payment plan id is empty ->' . json_encode($userData), $logFileName);
21940            return $result;
21941        }
21942
21943        // if empty price id
21944        if (!isset($userData['price_id'])) {
21945            $this->log(__METHOD__. ' user price id is empty ->' . json_encode($userData), $logFileName);
21946            return $result;
21947        }
21948
21949        $currencyCode = $userData['currency_code'];
21950        $paymentPlanId = $userData['payment_plan_id'];
21951
21952        // - NJ-18780 : fetch the retry payment plan data based on the user current plan
21953          # check if is lite plan user 
21954        $isLitePlanUser = in_array($paymentPlanId, Configure::read('lite_payment_plans')) ? true : false;
21955
21956        //- NJ-27262 chocotto plan
21957        $isChocottoPlanUser = in_array($paymentPlanId, [Configure::read('payment_plans.free_trial_chocotto'), Configure::read('payment_plans.chocotto_plan')]);
21958
21959
21960        // if card company is equals to apple or google
21961        if (in_array($userData['card_company'], array(Configure::read('card_company.apple'), Configure::read('card_company.google')))) {
21962            return $this->PaymentPlanPrice->getPaymentData(array(
21963                'currencyCode' => $currencyCode,
21964                'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
21965                'logFileName' => $logFileName
21966            ));
21967        // if corporate user
21968        } elseif (isset($userData['corporate_id']) && $userData['corporate_id'] && isset($userData['payment_plan_id'])) {
21969            // get corporate plan data
21970            $cpData = $this->getCorporatePaymentPlan($userData);
21971
21972            // if empty
21973            if (!$cpData) {
21974                return $result;
21975            }
21976            
21977            return array(
21978                'amount' => $cpData['amount'],
21979                'fAmount' => $cpData['fAmount'],
21980                'priceId' => $cpData['priceId'],
21981                'paymentPlanId' => $cpData['paymentPlanId']
21982            );
21983        } else {
21984            // if free trial
21985            if ($paymentPlanId == Configure::read('payment_plans.free_trial')) {
21986                $firstChargeDate = $userData['first_charge_date'];
21987
21988                // if first charge date is null or is equals to '0000-00-00 00:00:00'
21989                if (!isset($firstChargeDate) || $firstChargeDate == '0000-00-00 00:00:00') {
21990                    // get first charge date using payment history
21991                    $paymentData = $this->Payment->find('first', array(
21992                        'fields' => array('created'),
21993                        'conditions' => array(
21994                            'form_type' => array(1,2,4,6),
21995                            'user_id' => $userData['id'],
21996                            'param2' => ''
21997                        ),
21998                        'order' => 'id DESC'
21999                    ));
22000
22001                    // if empty
22002                    if (!$paymentData) {
22003                        $this->log(__METHOD__ . ' User has no first charge payment data. --> ' . json_encode($userData), $logFileName);
22004                        return $result;
22005                    }
22006                    $firstChargeDate = $paymentData['Payment']['created'];
22007                }
22008
22009                // get premium payment plan
22010                $premiumPlanData = $this->PaymentPlanPrice->getPaymentData(array(
22011                    'currencyCode' => $currencyCode,
22012                    'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
22013                    'datetime' => $firstChargeDate,
22014                    'logFileName' => $logFileName
22015                ));
22016
22017                // if empty
22018                if (!$premiumPlanData) {
22019                    return $result;
22020                }
22021
22022                $amount = $premiumPlanData['amount'];
22023                $priceId = $premiumPlanData['priceId'];
22024                $planStartDate = $premiumPlanData['planStartDate'];
22025            } else {
22026                if ($isLitePlanUser) {
22027                    // get premium payment plan
22028                    $lightPlanData = $this->PaymentPlanPrice->getPaymentData(array(
22029                        'currencyCode' => $currencyCode,
22030                        'paymentPlanId' => Configure::read('payment_plans.light_plan'),
22031                        // 'datetime' => $userData['first_charge_date'],
22032                        'logFileName' => $logFileName
22033                    ));
22034
22035                    // if empty
22036                    if (!$lightPlanData) {
22037                        $this->log(__METHOD__. ' Payment plan price data does not exist. --> ' . json_encode($userData) . ' price id --> ' , json_encode($priceId), $logFileName);
22038                        return $result;
22039                    }
22040
22041                    $amount = $lightPlanData['amount'];
22042                    $priceId = $lightPlanData['priceId'];
22043                    $planStartDate = $lightPlanData['planStartDate'];
22044                } elseif ($isChocottoPlanUser) {
22045                    // get chocotto payment plan
22046                    $chocottoPlanData = $this->PaymentPlanPrice->getPaymentData(array(
22047                        'currencyCode' => $currencyCode,
22048                        'paymentPlanId' => Configure::read('payment_plans.chocotto_plan'),
22049                        'logFileName' => $logFileName
22050                    ));
22051
22052                    // if empty
22053                    if (!$chocottoPlanData) {
22054                        $this->log(__METHOD__. ' Payment plan price data does not exist. --> ' . json_encode($userData) . ' price id --> ' , json_encode($priceId), $logFileName);
22055                        return $result;
22056                    }
22057
22058                    $amount = $chocottoPlanData['amount'];
22059                    $priceId = $chocottoPlanData['priceId'];
22060                    $planStartDate = $chocottoPlanData['planStartDate'];
22061                } else {
22062                    // get user payment plan
22063                    $data = $this->PaymentPlanPrice->find('first', array(
22064                        'fields' => array(
22065                            'amount',
22066                            'start_date'
22067                        ),
22068                        'conditions' => array('id' => $userData['price_id'])
22069                    ));
22070
22071                    // if empty
22072                    if (!$data) {
22073                        $this->log(__METHOD__. ' Payment plan price data does not exist. --> ' . json_encode($userData) . ' price id --> ' , json_encode($priceId), $logFileName);
22074                        return $result;
22075                    }
22076
22077                    $amount = $data['PaymentPlanPrice']['amount'];
22078                    $priceId = $userData['price_id'];
22079                    $planStartDate = $data['PaymentPlanPrice']['start_date'];
22080                }
22081            }
22082
22083            $_forcePlanID = Configure::read('payment_plans.premium_plan');
22084
22085            // - change plan to lite if already lite plan user 
22086            if ($isLitePlanUser) {
22087                $_forcePlanID = Configure::read('payment_plans.light_plan');
22088            }
22089
22090            // - change plan to chocotto if already chocotto plan user 
22091            if ($isChocottoPlanUser) {
22092                $_forcePlanID = Configure::read('payment_plans.chocotto_plan');
22093            }
22094
22095            // get force payment plan data
22096            $fuData = $this->PaymentPlanPrice->getPaymentData(array(
22097                'currencyCode' => $currencyCode,
22098                'paymentPlanId' => $_forcePlanID,
22099                'forceUpdate' => true,
22100                'logFileName' => $logFileName
22101            ));
22102
22103            // if force update
22104            if (
22105                isset($fuData['planStartDate'])
22106                && $fuData['planStartDate'] > $planStartDate
22107                && $fuData['priceId'] != $priceId
22108                && myTools::forceUpdateIncludeFreeTrial($paymentPlanId)
22109            ) {
22110                $result = $fuData;
22111            } else {
22112                $result = array(
22113                    'amount' => $amount,
22114                    'fAmount' => myTools::formatAmount($amount),
22115                    'priceId' => $priceId,
22116                    'paymentPlanId' => $_forcePlanID
22117                );
22118            }
22119        }
22120
22121        return $result;
22122    }
22123
22124    private function changePaymentPlanIfTelecomUser($user = array()) {
22125        if (isset($user['card_company']) && $user['card_company'] == Configure::read('card_company.telecom')) {
22126            // get zeus latest premium payment plan data
22127            $premiumPlan = $this->PaymentPlanPrice->getPaymentData(array(
22128                'currencyCode' => Configure::read('currency_jpy'),
22129                'paymentPlanId' => Configure::read('payment_plans.premium_plan')
22130            ));
22131
22132            if (!$premiumPlan) {
22133                return $user;
22134            }
22135
22136            // change user payment plan
22137            $user['payment_plan_id'] = $premiumPlan['paymentPlanId'];
22138            $user['price_id'] = $premiumPlan['priceId'];
22139        }
22140
22141        return $user;
22142    }
22143    /**
22144     * @api {get} /mobapp/notice/coupon_code_plan/:token notice_coupon_code_plan()
22145     * @apiName notice_coupon_code_plan
22146     * @apiGroup Payment
22147     * @apiDescription This endpoint is used to display the notice page for the coupon code plan.
22148     * 
22149     * @apiParam {String} token User token
22150     * 
22151     * @apiSuccess {View} Render Display the notice page for the coupon code plan.
22152     * 
22153     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage.
22154     * 
22155     * @apiSuccessExample Success Response:
22156     * Display the notice page for the coupon code plan.
22157     * 
22158     * @apiErrorExample Error Response:
22159     * Redirects to {{ENV}}/mobapp/retrypage.
22160     * 
22161     * @apiSampleRequest off
22162     */
22163    public function notice_coupon_code_plan() {
22164        $this->layout = 'mobapp';
22165        $this->set('title_for_layout', __('無料キャンペーン|オンライン英会話のネイティブキャンプ'));
22166        $this->complimentaryPlanValidation();
22167        $this->render(myTools::getDeviceUrl() . 'Static/notice_plan-coupon_code');
22168    }
22169    /**
22170     * @api {get} /mobapp/notice/coupon_code_plan_change/:token notice_coupon_code_plan_change()
22171     * @apiName notice_coupon_code_plan_change
22172     * @apiGroup Payment
22173     * @apiDescription This endpoint is used to display the notice page for the coupon code plan change.
22174     * 
22175     * @apiParam {String} token User token
22176     * 
22177     * @apiSuccess {View} Render Display the notice page for the coupon code plan change.
22178     * 
22179     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage.
22180     * 
22181     * @apiSuccessExample Success Response:
22182     * Display the notice page for the coupon code plan change.
22183     * 
22184     * @apiErrorExample Error Response:
22185     * Redirects to {{ENV}}/mobapp/retrypage.
22186     * 
22187     * @apiSampleRequest off
22188     */
22189    public function notice_coupon_code_plan_change() {
22190        $this->layout = 'mobapp';
22191        $user = $this->complimentaryPlanValidation();
22192        if ($user['card_company'] == Configure::read('card_company.zeus')) {
22193            $urlExtension = 'credit_charge';
22194        } else {
22195            $urlExtension = 'wp_credit_charge';
22196        }
22197
22198        $this->set('urlExtension', $urlExtension);
22199
22200        // - NJ-23812 : add redirection to the page
22201        $rediUrl = myTools::getUrl() . '/mobapp/payment/'.$urlExtension.myTools::getMobappToken($_GET);
22202        $this->redirect($rediUrl);
22203
22204        $this->render(myTools::getDeviceUrl() . 'Static/notice_coupon_code_plan_change');
22205    }
22206
22207    private function complimentaryPlanValidation() {
22208        $urlParams = myTools::getMobappToken($_GET);
22209        // if token is not set
22210        if (!$this->request->query['token']) {
22211            $this->log(__METHOD__.' token does not exist.', 'debug');
22212            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
22213        }
22214
22215        $token = $this->request->query['token'];
22216        $uData = $this->User->find('first', array(
22217            'fields' => array(
22218                'complimentary_code',
22219                'card_company'
22220            ),
22221            'conditions' => array('api_token' => $token),
22222            'recursive' => -1
22223        ));
22224
22225        if (!$uData) {
22226            $this->log(__METHOD__.' user does not exist.' . json_encode($token), 'debug');
22227            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
22228        }
22229
22230        // if not complimentary plan
22231        if (!isset($uData['User']['complimentary_code'])) {
22232            $this->log(__METHOD__.' user is not a complimentary plan.' . json_encode($token), 'debug');
22233            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
22234        }
22235
22236        // check if card company is not zeus or worldpay
22237        if (!in_array($uData['User']['card_company'], array(Configure::read('card_company.zeus'), Configure::read('card_company.worldpay')))) {
22238            $this->log(__METHOD__.' invalid user card company.' . json_encode($token), 'debug');
22239            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
22240        }
22241
22242        $this->set('token', $token);
22243        return $uData['User'];
22244    }
22245
22246    // NC-6593
22247    private function updateUserCardCompanyToZeus($userId) {
22248        $cardCompany = Configure::read('card_company.zeus');
22249        $this->User->validate = array();
22250        $this->User->read(array('card_company'), $userId);
22251        # set card_company
22252        $this->User->set('card_company', $cardCompany);
22253        # update userid
22254        return ($this->User->save());
22255    }
22256
22257    //NJ-69126 : private to public for unit test purposes
22258    public function slackWPErrorPostMsg($paymentHash = '', $userId = '', $errMsg = '', $paymentStatus = '') {
22259        $mySlack = new mySlack();
22260        $mySlack->channel = myTools::checkChannel("#nc-wp-fail", "#fdc-test-channel");
22261        $mySlack->username = "WP ERROR REPORT";
22262        $mySlack->link_names = true;
22263        $mySlack->text = "```";
22264        $mySlack->text .= "payment_hash: {$paymentHash}\n\n";
22265        $mySlack->text .= "payment_status: {$paymentStatus}\n\n";
22266        $mySlack->text .= "user_id: {$userId}\n\n";
22267        $mySlack->text .= "error: {$errMsg}\n\n";
22268        $mySlack->text .= "```";
22269        $mySlack->sendSlack();
22270    }
22271
22272    /**
22273     * Check if complimentary user
22274     * @param array $user
22275     * @return boolean $comPlanUser
22276     */
22277    private function ifComPlanUser($user = array()) {
22278        $comPlanUser = false;
22279
22280        // if has complimentary code
22281        if (isset($user['complimentary_code']) && trim($user['complimentary_code']) != '') {
22282            // set com_plan_user to true if payment plan id is not null and is complimentary plan
22283            if (isset($user['payment_plan_id']) && $user['payment_plan_id'] == Configure::read('payment_plans.complimentary_plan')){
22284                $comPlanUser = true;
22285            // set com_plan_user to true if payment plan id is null and is complimentary plan
22286            } elseif (!isset($user['payment_plan_id']) && $this->Payment->ifComPlanUser($user['id'])) {
22287                $comPlanUser = true;
22288            }
22289        }
22290
22291        return $comPlanUser;
22292    }
22293
22294    private function getCorporatePaymentPlan($userData = array(),$params = array()) {
22295        $planData = array();
22296        $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($userData['payment_plan_id']);
22297        $corporateIndiUser = false;
22298
22299        // get corporate admin payment method
22300        $corporateAdminData = $this->Corporate->find('first', array(
22301            'fields' => array('payment_method'),
22302            'conditions' => array(
22303                'id' => $userData['corporate_id'],
22304                'status' => 1
22305            ),
22306            'recursive' => -1
22307        ));
22308
22309        if (!$corporateAdminData) {
22310            return $planData;
22311        }
22312
22313        // set corporate admin payment method;
22314        $caPaymentMethod = $corporateAdminData['Corporate']['payment_method'];
22315
22316        $ppIdParams = array(
22317            'corporateType' => isset($corporateType) ? $corporateType : $params['corporate_type'],
22318            'paymentMethod' => $caPaymentMethod
22319        );
22320
22321        $paymentPlanId = $this->PaymentPlanPrice->getCorporateUserPaymentPlanId($ppIdParams);
22322
22323        if(
22324            empty($paymentPlanId) && // payment planid empty
22325            (!isset($params['corporate_type']) || !$params['corporate_type']) && // no corporate type data
22326            $caPaymentMethod == 1 // // individual
22327        ) {
22328            $paymentPlanId = $this->getDefaultPlanId($userData['corporate_id']);
22329        }
22330
22331        if (!isset($paymentPlanId)) {
22332            return $planData;
22333        }
22334
22335        // get corporate plan data
22336        $planData = $this->PaymentPlanPrice->getPaymentData(array(
22337            'currencyCode' => $userData['currency_code'],
22338            'paymentPlanId' => $paymentPlanId,
22339            'logFileName' => 'card_charge'
22340        ));
22341
22342        if ($planData) {
22343            $planData['corporateIndiUser'] = $caPaymentMethod == 1 ? true : false;
22344        }
22345
22346        return $planData;
22347    }
22348    /**
22349     * @api {post} /mobapp/corporate_register_card/:token mobapp_corporate_register_card()
22350     * @apiName mobapp_corporate_register_card
22351     * @apiGroup Payment
22352     * @apiDescription This endpoint is used to register a corporate user's credit card.
22353     * 
22354     * @apiParam {String} token The user's token
22355     * 
22356     * @apiBody {Number} cardnumber The credit card number
22357     * @apiBody {Number} expyy The credit card expiration year
22358     * @apiBody {Number} expmm The credit card expiration month
22359     * @apiBody {String} username The credit card holder's name
22360     * @apiBody {String} zeusTokenValue The zeus token value
22361     * 
22362     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/close?token={{token}}&corporate_register_card=1 if successful.
22363     * 
22364     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage{{urlParams}} if the token is missing / if user does not exist or not a corporate user.
22365     * 
22366     * @apiExample Example usage:
22367     * {
22368     *         "cardnumber": 4444333322221111,
22369     *         "expyy": 2028,
22370     *         "expmm": 12,
22371     *         "username": "John Doe",
22372     *         "zeusTokenValue": "zeusTokenValue"
22373     * }
22374     * 
22375     * @apiSuccessExample Success Response:
22376     * Redirects to {{ENV}}/mobapp/close?token={{token}}&corporate_register_card=1
22377     * 
22378     * @apiErrorExample Error Response:
22379     * Redirects to {{ENV}}/mobapp/retrypage{{urlParams}}
22380     * 
22381     * @apiSampleRequest off
22382     */
22383    public function mobapp_corporate_register_card() {
22384        $this->layout = "mobapp";
22385        $urlParams = myTools::getMobappToken($_GET);
22386
22387        // redirect to retry page if parameter token does not exist
22388        if (!isset($this->request->query['token'])) {
22389            $this->log(__METHOD__ . ' missing parameter token. --> ' . json_encode($urlParams), 'debug');
22390            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
22391        }
22392
22393        $apiToken = $this->request->query['token'];
22394        $conditions = array(
22395            'api_token' => $apiToken,
22396            'corporate_id IS NOT NULL',
22397            'payment_plan_id IS NOT NULL',
22398            // 'card_company IS NULL',
22399            // 'card_brand IS NULL',
22400            // 'card_number IS NULL'
22401        );
22402
22403        // get user data
22404        $userData = $this->User->getUserData($conditions, array('*'), 'first');
22405        $userObj = new UserTable($userData['User']);
22406        $fromPage = 'reservation';
22407        if (
22408            !empty($userData['User']['corporate_id']) && 
22409            in_array($userObj->getMembershipTypeIndex(), Configure::read('common_corporate_payment_memberships'))
22410        ) {
22411            return $this->redirect(myTools::getUrl() . '/mobapp/common_corporate_payment?type='. Configure::read('payment_url_type.corporate_type.corporate_register_card') .'&token=' . $apiToken . '&from_page=' . $fromPage);
22412        }
22413
22414        // redirect to retry page if does not exist or exist but not corporate user
22415        if (!$userData) {
22416            $this->log(__METHOD__ . ' user doest not exist or exist but not a corporate users. --> ' . json_encode($urlParams), 'debug');
22417            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
22418        }
22419
22420        $registerCardError = false;
22421        if ($this->request->is('post')) {
22422            $postData = $this->request->data;
22423            $this->set('data', $postData);
22424            $userData = $userData['User'];
22425
22426            // get form information
22427            $data = $postData['ZPaymentFullLogs'];
22428            //- set user id
22429            $userId = $userData['id'];
22430            //- default amount
22431            $paymentAmount = 0;
22432
22433            // get receivable reservation payment
22434            $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userId);
22435            if ($receivablePayment) {
22436                $paymentAmount += $receivablePayment;
22437            }
22438
22439            // get appreciation receivable payments
22440            $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('appreciation_data.payment_element_type'));
22441            if ($appreciationReceivable) {
22442                $paymentAmount += $appreciationReceivable;
22443            }    
22444
22445            // set payment params
22446            $paymentParams = array(
22447                'currencyCode' => $userData['currency_code'],
22448                'paymentPlanId' => $userData['payment_plan_id'],
22449                'priceId' => $userData['price_id'],
22450                'remoteAddress' => $_SERVER["REMOTE_ADDR"],
22451                'formType' => Configure::read('corporate_credit_card_registration'),
22452                'paymentType' => Configure::read('payment_types.payment_plan'),
22453                'paymentAmount' => $paymentAmount,
22454                'logFileName' => 'corporate_credit_card_registration',
22455                'corporateSettlementType' => Configure::read('corporate_settlement_types.corporate_card_registration')
22456            );
22457
22458            // card expiration date
22459            if (isset($data['expyy']) && isset($data['expmm'])) {
22460                $paymentParams['cardExpirationDate'] = array('cardExpirationDate' => date('Y-m-t', strtotime($data['expyy'] . '-' . $data['expmm'])));
22461            }
22462
22463            $ptParams = array(
22464                'user_id' => $userId,
22465                'payment_hash' => myTools::generateOrderCode($userId),
22466                'payment_params' => json_encode($paymentParams),
22467                'course_id' => Configure::read("credit.course_id")
22468            );
22469
22470            if ($pt = $this->PaymentTransaction->setWPPaymentTransaction($ptParams)) {
22471
22472                $zeuspayData = array(
22473                    'clientIp' => Configure::read('ZEUS_clientip'), # clientip, # clientip
22474                    'cardNumber' => isset($data['cardnumber']) ? (int) $data['cardnumber'] : null,
22475                    'expyy' => isset($data['expyy']) ? (int) $data['expyy'] : null,
22476                    'expmm' => isset($data['expmm']) ? (int) $data['expmm'] : null,
22477                    'telNo' => Configure::read('credit.default_telno'), # telephone number
22478                    'email' => $userData['email'], # email
22479                    'username' => mb_strtoupper($data['username']), # username
22480                    'sendId' => $userId, # id
22481                    'money' => $paymentAmount, # money
22482                    'tokenKey' => $data['zeusTokenValue'],
22483                    'paymentHash' => $pt['payment_hash']
22484                );
22485
22486                // send curl request
22487                $paymentResponse =$this->ZCharge->charge_regist(json_encode($zeuspayData));
22488
22489                if ($paymentResponse[0] == "Success_order" || $paymentResponse == "Success_order") {
22490                    return $this->redirect(myTools::getUrl() . '/mobapp/close?token=' . $apiToken . '&corporate_register_card=1');
22491                }
22492            }
22493
22494            $registerCardError = true;
22495        }
22496
22497        $this->set('title_for_layout', '新規会員登録|オンライン英会話のネイティブキャンプ');
22498        $this->set('zeusTransactionFlag', true);
22499        $this->set('registerCardError', $registerCardError);
22500        $this->set('amount', $paymentAmount);
22501        $this->set('paymentHash', $pt['payment_hash']);
22502        $this->render(myTools::getDeviceUrl() . 'Payment/corporate_register_form');
22503    }
22504
22505    // NJ-69193 ~ private to public to easily access via unit test
22506    public function slackZeusErrorPostMsg($type = '', $line = '', $method = '', $userId = '', $failMessage='', $debugData = array(), $moreDebugData = array()) {
22507        $mySlack = new mySlack();
22508        $mySlack->channel = myTools::checkChannel("#nc-settlement", "#nc-settlement-dev");
22509        $mySlack->username = "NC Payment Failed";
22510        $mySlack->text = "```";
22511        $mySlack->text .= "ROLLBACK TYPE:\n";
22512        $mySlack->text .= $type . "\n\n";
22513        $mySlack->text .= "LINE NUMBER:\n";
22514        $mySlack->text .= $line . "\n\n";
22515        $mySlack->text .= "METHOD:\n";
22516        $mySlack->text .= $method . "\n\n";
22517        $mySlack->text .= "USER ID:\n";
22518        $mySlack->text .= $userId . "\n\n";
22519        $mySlack->text .= "KICKBACK URL:\n";
22520        $mySlack->text .= $_SERVER['REQUEST_URI'] . "\n\n";
22521        $mySlack->text .= "EC2 INSTANCE ID:\n";
22522        $mySlack->text .= exec('ec2-metadata -i') . "\n\n";
22523        $mySlack->text .= "REASON OF FAILURE:\n";
22524        $mySlack->text .= date("Y-m-d H:i:s") . " " . $failMessage."\n";
22525        $mySlack->text .= json_encode($debugData);
22526        if (!empty($moreDebugData)) {
22527            $mySlack->text .= "\n" . json_encode($moreDebugData);
22528        }
22529        $mySlack->text .= "```";
22530        $mySlack->sendSlack();
22531    }
22532
22533    private function processPayPalPayment($data = array(), $userData = array()) {
22534        $logFileName = 'paypal_debug';
22535
22536        $memKey = 'paypalBillingAgreementData_' . $userData['api_token'];
22537        // return false if memcache billing agreement data does not exist
22538        if (!$paypalData = $this->memcache->get($memKey)) {
22539            $this->log(__METHOD__ . ' Memcached billing agreement data does not exist. --> ' . json_encode($paypalData) . ' | data --> ' . json_encode($data) . ' | user data --> ' . json_encode($userData), $logFileName);
22540            return false;
22541        }
22542
22543        if (
22544            !isset($paypalData['accessTokenData']['access_token']) || 
22545            !isset($paypalData['finalizeBillingAgreementData']['id']) ||
22546            !isset($paypalData['finalizeBillingAgreementData']['payer']['payer_info']['payer_id'])
22547        ) {
22548            $this->log(__METHOD__ . ' Missing billing agreement param(s). --> ' . json_encode($paypalData), $logFileName);
22549            return false;
22550        }
22551
22552        $accessToken = $paypalData['accessTokenData']['access_token'];
22553        $baId = $paypalData['finalizeBillingAgreementData']['id']; // billing agreement id
22554        $payerId = $paypalData['finalizeBillingAgreementData']['payer']['payer_info']['payer_id'];
22555        $payerEmail = $paypalData['finalizeBillingAgreementData']['payer']['payer_info']['email'];
22556        $formType = $data['formType'];
22557        $monthlyPayment = 0;
22558        if(isset($data['ZPaymentFullLogs']['money'])){
22559            $monthlyPayment = $data['ZPaymentFullLogs']['money'];
22560        }else if(isset($data['paymentPlanData']['amount'])){
22561            $monthlyPayment = $data['paymentPlanData']['amount'];
22562        }
22563        $discountedAmount = 0;
22564
22565        // if using coupon
22566        if (isset($data['monthlyDiscount']) && $formType == Configure::read('payment_credit_retry')) {
22567            $discountedAmount = $userData['discounted_amount'] = $data['monthlyDiscount'];
22568            $userData['monthlyDiscount'] = $data['monthlyDiscount'];
22569            $userData['monthly_grp_id'] = isset($data['monthly_grp_id']) ? $data['monthly_grp_id'] : 0;
22570            $monthlyPayment -= $data['monthlyDiscount'];
22571        }
22572
22573        // if using coupon during force settlement
22574        if (!empty($data['couponUseSettlement']['useCouponAmount']) && in_array($formType, Configure::read('allow_coupon.settlement_form_type'))) {
22575            $discountedAmount += $data['couponUseSettlement']['useCouponAmount'];
22576            $userData['couponUseSettlement'] = $data['couponUseSettlement'];
22577            $monthlyPayment -= $data['couponUseSettlement']['useCouponAmount'];
22578        }
22579
22580        // If retry and has annual discount
22581        if ($formType == Configure::read('payment_credit_retry') || $formType == Configure::read('payment_credit_force_charge')) {
22582            // get user active annual discount option
22583            $annualDiscountOptionData = $this->UserDiscountOptionsTerm->getTerm([
22584                'user_id' => $userData['id'],
22585                'discount_option_id' => Configure::read('discount_option.annual.plan_id'),
22586                'status' => 1
22587            ]);
22588
22589            if ($annualDiscountOptionData) {
22590                unset($annualDiscountOptionData['contract_start']);
22591                $annualDiscountOptionData += [
22592                    'dosh_event' => Configure::read('discount_option.dosh_event.annual_discount'),
22593                    'dosh_status' => Configure::read('discount_option.dosh_status.monthly_discount')
22594                ];
22595                $data['discountOption'] = $annualDiscountOptionData;
22596            }
22597        }
22598
22599        $receivablePayment = $data['receivablePayment'];
22600        $appreciationReceivable = $data['appreciationReceivable'];
22601        $liveLessonReceivable = $data['liveLessonReceivable'];
22602        $totalAmount =  $monthlyPayment + $receivablePayment + $appreciationReceivable + $liveLessonReceivable;
22603
22604        // if has discount option
22605        if (isset($data['discountOption'])) {
22606            $totalAmount -= $data['discountOption']['amount'];
22607            $userData['discountOption'] = $data['discountOption'];
22608            $monthlyPayment -= $data['discountOption']['amount'];
22609        }
22610
22611        $userData['payment_plan_id'] = $paymentPlanId = $data['paymentPlanData']['paymentPlanId'];
22612        $userData['price_id'] = $priceId = $data['paymentPlanData']['priceId'];
22613        $userData['paymentAmount'] = $totalAmount;
22614
22615        // return false if failed to create payment transaction
22616        if (!$pt = $this->createPaymentTransaction($formType, $userData)) {
22617            $this->log(__METHOD__ .' Failed to create payment transaction. Params --> ' . json_encode($userData), $logFileName);
22618            return false;
22619        }
22620
22621        $paymentHash = $pt['payment_hash'];
22622        $ptPassword = $pt['password'];
22623        $ptPaymentParams = json_decode($pt['payment_params'], true);
22624        $platform = isset($ptPaymentParams['platform']) ? $ptPaymentParams['platform'] : null;
22625        $ptId = $pt['id'];
22626        $userId = $userData['id'];
22627        $cardCompany = Configure::read('card_company.paypal');
22628        $currencyId = Configure::read('default.settlement_currency_id');  // set currency id to jpy
22629        $currencyCode = Configure::read('default.user_currency');
22630        $paymentType = Configure::read('payment_types.payment_plan');
22631        $dateNow = date('Y-m-d H:i:s');
22632        $ftForceCharge = Configure::read('payment_credit_force_charge');
22633        $ftRetry = Configure::read('payment_credit_retry');
22634        $ftCardAuth = Configure::read('payment_credit_authentication');
22635        $membershipStatusIndex = UserTable::getStudentMembershipStatus($userId);
22636        $currency_before = $currencyCode;
22637        $plan_before = $paymentPlanId;
22638        $appreciationFlg = 0;
22639        $tipAmount = null;
22640
22641        $ftLitePlanPaid = Configure::read('payment_lite_credit_paid');
22642        $isLitePlanUser = in_array($paymentPlanId, Configure::read('lite_payment_plans')) ? true : false;
22643
22644        //- NJ-27262 chocotto plans
22645        $ftChocottoPlanFree = Configure::read('payment_credit_chocotto_free');
22646        $ftChocottoPlanPaid = Configure::read('payment_credit_chocotto_monthly_payment');
22647        $ftChocottoPlanRetry = Configure::read('payment_credit_chocotto_retry');
22648        $ftChocottoPlanForceCharge = Configure::read('payment_credit_chocotto_force_charge');
22649
22650        $isChocottoPlanUser = in_array(
22651            $paymentPlanId,
22652            [
22653                Configure::read('payment_plans.free_trial_chocotto'),
22654                Configure::read('payment_plans.chocotto_plan')
22655            ]
22656        );
22657
22658        // load PayPal class
22659        if (!class_exists('PayPal')) {
22660            App::import('Lib', 'PayPal');
22661        }
22662
22663        $paypal = new PayPal();
22664
22665        $createOrderParams = array(
22666            'accessToken' => $accessToken,
22667            'paypalRequestId' => $ptId,
22668            'intent' => 'CAPTURE',
22669            'paymentHash' => $paymentHash,
22670            'userId' => $userId,
22671            'currencyCode' => $currencyCode,
22672            'amount' => (int)$totalAmount,
22673            'billingAgreementId' => $baId
22674        );
22675
22676        // create order
22677        $createOrderResult = $paypal->createOrder($createOrderParams);
22678        $paypalData['create_order_data'] = $createOrderResult;
22679
22680        // save settlement history for tracking
22681        if (!SettlementHistoryTable::add(array(
22682                'userId' => $userId,
22683                'params' => json_encode($paypalData),
22684                'createdIp' => $dateNow,
22685                'modifiedIp' => $dateNow
22686            )
22687        )) {
22688            $this->log(__METHOD__ . ' Failed to save paypal result data in settlement history. ' . json_encode($paypalData), $logFileName);
22689            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save paypal result data in settlement history', $paypalData);
22690            return false;
22691        }
22692
22693        // If retry payment and zero payment
22694        if (
22695            in_array(
22696                $formType, 
22697                [
22698                    Configure::read('payment_credit_retry'),
22699                    Configure::read('payment_credit_chocotto_retry')
22700                ]
22701            ) && 
22702            $totalAmount <= 0
22703        ) {
22704            $zeroPaymentParams = array(
22705                'paymentHash' => $paymentHash,
22706                'userId' => $userId,
22707                'money' => $totalAmount,
22708                'cardCompany' => $cardCompany,
22709                'controllerName' => 'Payment',
22710                'actionName' => 'processPayPalPayment',
22711                'logFileName' => 'card_retry'
22712            );
22713            if (!$this->Payment->zeroPayment($zeroPaymentParams)) {
22714                $this->log(__METHOD__ . ' Failed to save payment data. ' . json_encode($zeroPaymentParams) . ' -- ' . json_encode($data), $logFileName);
22715                return false;
22716            }
22717
22718            // Check if has annual discount then insert monthly discount option after 0 payment
22719            if (isset($data['discountOption'])) {
22720                $discountOption = isset($data['discountOption']) ? $data['discountOption'] : [];
22721        
22722                $discountOption += [
22723                    'contract_start' => $contractStart,
22724                    'currency_code' => $currencyCode,
22725                    'payment_id' => $this->Payment->id,
22726                    'dosh_settlement_status' => 1, // success
22727                    'form_type' => $formType
22728                ];
22729
22730                if (!$this->UserDiscountOptionsTerm->processMonthlyDiscountOption($discountOption)) {
22731                    $this->log(__METHOD__ . ' Failed to process monthly discount option. ' . json_encode($discountOption), $logFileName);
22732                    return false;
22733                }
22734            }
22735
22736            return true;
22737        }
22738
22739        if (isset($createOrderResult['status']) && $createOrderResult['status'] === 'COMPLETED') {
22740            $paymentData = array(
22741                'user_id' => $userId,
22742                'amount' => $monthlyPayment,
22743                'status' => 1,
22744                'reference_id' => $userId,
22745                'payment_transaction_password' => $ptPassword,
22746                'card_company' => $cardCompany,
22747                'param1' => json_encode($paypalData),
22748                'form_type' => $formType,
22749                'ordd' => $paymentHash,
22750                'transaction_code' => $paymentHash,
22751                'currency_id' => $currencyId,
22752                'currency_code' => $currencyCode,
22753                'payment_id' => $paymentPlanId,
22754                'price_id' => $priceId,
22755                'payment_type' => $paymentType,
22756                'discounted_amount' => $discountedAmount
22757            );
22758
22759            $forceSettlementWithCoupon = false;
22760            // NJ-47740 - set used coupon
22761            if (
22762                !empty($data['couponUseSettlement']) && 
22763                !empty($data['couponUseSettlement']['useCouponAmount']) && 
22764                in_array($formType, Configure::read('allow_coupon.settlement_form_type'))
22765            ) {
22766                $couponData = $data['couponUseSettlement'];
22767                $couponData['nextChargeDate'] = date('Y-m-d');
22768                $couponData['request_result'] = true;
22769                
22770                $result_coupon_use = $this->UsersCouponV1->performCouponUse($couponData);
22771                $result_coupon_use = !empty($result_coupon_use) ? json_decode($result_coupon_use,true) : array();
22772                
22773                if (isset($result_coupon_use['cgrp_id'])) {
22774                    $paymentData['discounted_amount'] = $data['couponUseSettlement']['useCouponAmount'];
22775                    $paymentData['coupon_request_id'] = $result_coupon_use['cgrp_id'];
22776                    $forceSettlementWithCoupon = true;
22777                }
22778            } else if (isset($userData['monthly_grp_id'])) {
22779                $paymentData['coupon_request_id'] = $userData['monthly_grp_id'];
22780            }
22781            // NJ-47740 end
22782            
22783            $discountOption = isset($ptPaymentParams['discountOption']) ? $ptPaymentParams['discountOption'] : [];
22784    
22785            if (!empty($discountOption)) {
22786                $paymentData['discount_option_price_id'] = $discountOption['discount_option_price_id'];
22787            }
22788
22789            // create new payment
22790            $this->Payment->clear();
22791            $this->Payment->create();
22792            $this->Payment->set($paymentData);
22793            $this->Payment->validate = array();
22794
22795            // check if payment was not saved
22796            if (!$this->Payment->save()) {
22797                $this->log(__METHOD__ . ' Failed to save payment data. ' . json_encode($paymentData) . ' -- ' . json_encode($data), $logFileName);
22798                
22799                if ($forceSettlementWithCoupon) {
22800                    $couponUnconfirmData = array(
22801                        'grpId' => $paymentData['coupon_request_id'],
22802                        'userId' => $userId,
22803                        'kbn' => Configure::read('coupon_kbn.monthly_settlement')
22804                    );
22805                    
22806                    $res_unconfirm = $this->UsersCouponV1->performCouponUnconfirm($couponUnconfirmData);
22807                    
22808                    if (empty($res_unconfirm)) {
22809                        $this->log(__METHOD__ . ' failed to perform coupon unconfirm data. '. json_encode($couponUnconfirmData), $logFileName);
22810                    }
22811                }
22812                return false;
22813            }
22814
22815            $paymentId = $this->Payment->id;
22816            
22817            // NJ-47740
22818            if (!empty($paymentData['coupon_request_id']) && $paymentData['discounted_amount'] > 0) {
22819                // confirm coupon use request for discount
22820                $requestCouponConfirmData = array(
22821                    'grpId' => $paymentData['coupon_request_id'],
22822                    'paymentId' => $paymentId
22823                );
22824                $result_confirm = $this->UsersCouponV1->performCouponConfirm($requestCouponConfirmData);
22825                
22826                if (!$result_confirm) {
22827                    $this->log(__METHOD__ . ' Failed to confirm coupon use request. ' . json_encode($requestCouponConfirmData) . ' -- ' . json_encode($data), $logFileName);
22828                }
22829            }
22830            // NJ-47740 end
22831
22832            // update payment details
22833            $updatePaymentDetailParams = array(
22834                'currencyCode' => $paymentData['currency_code'],
22835                'formType' => $paymentData['form_type'],
22836                'paymentType' => $paymentData['payment_type'],
22837                'amount' => $paymentData['amount'],
22838                'discounted_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0,
22839                'familyId' => $userData['parent_id'],
22840                'cronDateRun' => $dateNow,
22841                'priceId' => $paymentData['price_id'],
22842                'paymentPlanId' => $paymentData['payment_id'],
22843                'user_id' => $paymentData['user_id'],
22844                'coupon_use_request_id' => isset($paymentData['coupon_request_id']) ? $paymentData['coupon_request_id'] : null,
22845                'coupon_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0
22846            );
22847
22848            if (!empty($discountOption)) {
22849                $updatePaymentDetailParams['discount_option_price_id'] = $discountOption['discount_option_price_id'];
22850                $updatePaymentDetailParams['discount_option_amount'] = $discountOption['amount'];
22851            }
22852
22853            $updatePaymentDetail = array(
22854                'id' => $ptId,
22855                'fields' => array(
22856                    'payment_details' => $updatePaymentDetailParams
22857                )
22858            );
22859
22860            if (!$this->PaymentTransaction->updateWPPaymentTransaction($updatePaymentDetail)) {
22861                $this->log(__METHOD__ . ' Failed to update payment details. ' . json_encode($updatePaymentDetail), $logFileName);
22862            }
22863            
22864            //update/add user`s settlement amount
22865            $this->User->updateUserPayments($paymentData);
22866
22867            // set transaction
22868            $dataSource = $this->User->getDataSource();
22869            $dataSource->begin();
22870
22871            // user array to be saved
22872            $saveUserArr = array(
22873                'status' => 1,
22874                'modified' => $dateNow,
22875                'fail_flg' => 0,
22876                'charge_flg' => 1,
22877                'counseling_attended_flg' => 0,
22878                'card_company' => $cardCompany,
22879                'hash16' => $userId,
22880                'last_charge_date' => $dateNow,
22881                'payment_plan_id' => $paymentPlanId,
22882                'price_id' => $priceId,
22883                'corporate_id' => null,
22884                'corporate_type' => null,
22885                'paypal_payer_id' => $payerId,
22886                'paypal_billing_agreement_id' => $baId,
22887                'card_expiration_date' => null,
22888                'paypal_payer_email' => $payerEmail
22889            );
22890
22891            if (in_array(
22892                $formType, 
22893                array(
22894                    $ftForceCharge,
22895                    $ftRetry,
22896                    $ftLitePlanPaid,
22897                    $ftChocottoPlanPaid,
22898                    $ftChocottoPlanRetry,
22899                    $ftChocottoPlanForceCharge
22900                )
22901            )) {
22902                // get and set next charge date
22903                $nextChargeDate = $this->User->getNextChargeDate();
22904                $saveUserArr['next_charge_date'] = $nextChargeDate;
22905                $saveUserArr['double_check_flg'] = 1;
22906                $saveUserArr['expired_card_flg'] = 0;
22907
22908                // give points to user join the campaign who retry payment
22909                if ($formType == $ftRetry) {
22910                    $this->loadModel("ContinuationCampaign");
22911                    $this->ContinuationCampaign->givePointsRetrySuccess(array('user_ids' => array($userId)));
22912                }
22913            } elseif ($formType == $ftCardAuth) {
22914                $saveUserArr['first_charge_date'] = $dateNow;
22915                $saveUserArr['platform'] = $platform;
22916
22917                // normal user
22918                $nextChargeDate = $this->User->getFirstNextChargeDate();
22919                $saveUserArr['next_charge_date'] = $nextChargeDate;
22920            }
22921            //NJ-7874 if appreciation flag and amount is set
22922            if (isset($ptPaymentParams['family_data']['applyPlan']['tip_max_amount']) && $ptPaymentParams['family_data']['applyPlan']['tip_max_amount']) {
22923                $tipAmount = $ptPaymentParams['family_data']['applyPlan']['tip_max_amount'];
22924            }
22925
22926            if (isset($ptPaymentParams['family_data']['applyPlan']['allow_appreciation_flg']) && $ptPaymentParams['family_data']['applyPlan']['allow_appreciation_flg'] && $tipAmount) {
22927                $appreciationFlg = 1;
22928            }
22929
22930            // NJ-1562 - appreciation on
22931            if( $paymentPlanId && in_array( $paymentPlanId, Configure::read('appreciation.payment_plan_id') ) ) {
22932                $saveUserArr['allow_appreciation_flg'] = 1; // on
22933
22934                //NJ-7874 Turn Off appreciation settings for Family Plan (Default)
22935                if (in_array($paymentPlanId, Configure::read('appreciation.can_coin_purchase_check')) ) {
22936                    $saveUserArr['allow_appreciation_flg'] = $appreciationFlg;
22937                    $saveUserArr['show_appreciation_flg'] = $appreciationFlg;
22938                    $saveUserArr['tip_max_amount'] = $tipAmount;
22939                } else {
22940                    //NJ-7548 : fetch the birthday and age
22941                    $userBirthday  = $userData['User']['birthday'] ?? $userData['birthday'];
22942                    $userAge = UserTable::getStudentAge($userBirthday);
22943                    $userAge = $userAge ? (int) $userAge : null;
22944
22945                    //show appreciation flg default
22946                    $showAppreciationFlg = 0;
22947
22948                    //change the show appreciation flg if no birthday set or 18 and above            
22949                    if (!$userAge || $userAge >= 18) {
22950                        $showAppreciationFlg = 1;
22951                    }
22952
22953                    $saveUserArr['show_appreciation_flg'] = $showAppreciationFlg;
22954                }
22955            }
22956
22957            // NC-7779 : check if user has chivox monthly test taken for the current month, and monthly_speaking_attended_flg ON,
22958            // turn Off the flag if users has not yet taken the exam for the current month.
22959            // @TODO check query
22960            if (
22961                isset($userData['monthly_speaking_attended_flg']) && isset($userData['monthly_speaking_business_attended_flg'])
22962                && ($userData['monthly_speaking_attended_flg'] == 1 || $userData['monthly_speaking_business_attended_flg'] == 1)
22963            ) {
22964                // check chivox monthly
22965                $paymentPlanIdsForChivoxMonthly = Configure::read('chivox.monthly.user_payment_plan_cantake_exam');
22966                if (in_array($paymentPlanId, $paymentPlanIdsForChivoxMonthly)) {
22967
22968                    // load model
22969                    $this->loadModel("UsersChivoxMonthlyTest");
22970
22971                    $userTestMonthFlag = $this->UsersChivoxMonthlyTest->checkUserCurrentMonthExam(array('user_id' => $userId));
22972                    $monthlySpeakingAttendedFlg = Configure::read('chivox.test_data_test_type.daily'); // test_type daily speaking 0
22973                    $monthlySpeakingBusinessAttendedFlg = Configure::read('chivox.test_data_test_type.business'); // test_type business 1
22974
22975                    // if user hat not yet taken the exam for current month
22976                    if (!in_array($monthlySpeakingAttendedFlg, $userTestMonthFlag)) {
22977                        $saveUserArr['monthly_speaking_attended_flg'] = 0;
22978                    }
22979                    if (!in_array($monthlySpeakingBusinessAttendedFlg, $userTestMonthFlag)) {
22980                        $saveUserArr['monthly_speaking_business_attended_flg'] = 0;
22981                    }
22982                }
22983            }
22984
22985            // update the user information
22986            $this->User->validate = array();
22987            if (!$read = $this->User->read(array_keys($saveUserArr), $userId)) {
22988                $this->log(__METHOD__ . ' User id does not exist. ' . json_encode($userData) . ' -- ' . json_encode($createOrderResult), $logFileName);
22989                $dataSource->rollback();
22990                return false;
22991            }
22992
22993            $this->User->set($saveUserArr);
22994            if (!$this->User->save()) {
22995                $this->log(__METHOD__ . ' Failed update user data. ' . json_encode($saveUserArr) . ' -- ' . json_encode($createOrderResult), $logFileName);
22996                $dataSource->rollback();
22997                return false;
22998            }
22999
23000            // check if membership status was change
23001            if (isset($ptPaymentParams['statusBefore']) && isset($ptPaymentParams['statusAfter']) && isset($ptPaymentParams['platform'])) {
23002                $currentUser = $this->User->find('first', array(
23003                    'fields' => array('User.parent_id', 'User.currency_code', 'User.payment_plan_id'),
23004                    'conditions' => array('User.id' => $userId),
23005                    'recursive' => -1
23006                ));
23007                $parentId = $currentUser['User']['parent_id'];
23008                $is_cron = 0;
23009                if (php_sapi_name() == 'cli'){
23010                    $is_cron = 1;
23011                } 
23012                   $currency_after = $currentUser['User']['currency_code'];
23013                   $plan_after = $currentUser['User']['payment_plan_id'];
23014
23015                $usclData = array(
23016                    'user_id' => $userId,
23017                    'platform' => $platform ?? '',
23018                    'card_company_before' => $userData['card_company'],
23019                    'status_before' => $ptPaymentParams['statusBefore'],
23020                    'status_after' => $ptPaymentParams['statusAfter'],
23021                    'controller_name' => $this->request->params['controller'],
23022                    'action_name' => $this->request->params['action'],
23023                    'parent_id' => $parentId,
23024                    'is_cron' => $is_cron,
23025                    'currency_before' => $currency_before,
23026                    'currency_after' => $currency_after,
23027                    'payment_plan_id_before' => $plan_before,
23028                    'payment_plan_id_after' => $plan_after,
23029                    'default_appreciation_flg' => $appreciationFlg,
23030                    'default_appreciation_amount' => $tipAmount
23031                );
23032                // save user change membership status
23033                if (!$this->UserStatusChangeLog->saveLog($usclData)) {
23034                    $dataSource->rollback();
23035                    return false;
23036                }
23037            }
23038
23039            // if has receivable payment
23040            if ($receivablePayment) {
23041                // set payment id
23042                $data["payment_id"] = $paymentId;
23043
23044                $paymentData = array(
23045                    'user_id' => $userId,
23046                    'amount' => $receivablePayment,
23047                    'status' => 1,
23048                    'type_id' => 1,
23049                    'reference_id' => $userId,
23050                    'card_company' => $cardCompany,
23051                    'param1' => json_encode($data),
23052                    'form_type' => Configure::read('payment_credit_receivable'),
23053                    'ordd' => $paymentHash,
23054                    'currency_code' => $currencyCode,
23055                    'transaction_code' => $paymentHash,
23056                    'price_id' => $priceId,
23057                    'payment_id' => $paymentPlanId,
23058                    'payment_type' => $paymentType,
23059                    'discounted_amount' => $discountedAmount
23060                );
23061
23062                // create new payment
23063                $this->Payment->clear();
23064                $this->Payment->create();
23065                $this->Payment->set($paymentData);
23066                $this->Payment->validate = array();
23067
23068                if (!$this->Payment->save()) {
23069                    $this->log(__METHOD__ . ' Failed to save payment data for receivable.' . json_encode($paymentData), $logFileName);
23070                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data for receivable.', $paymentData);
23071                    $dataSource->rollback();
23072                    return false;
23073                }
23074
23075                //update/add user`s settlement amount
23076                $this->User->updateUserPayments($paymentData);
23077                // set payment_id
23078                $receivablePaymentId = $this->Payment->id;
23079
23080                // set payment receivable statuses to 2 - received
23081                $this->PaymentReceivable->updateReceivableReservationPayment(
23082                    $userId,
23083                    array(
23084                        'status' => 2,
23085                        'payment_id' => $receivablePaymentId,
23086                        'payment_collection_date' => date("Y-m-d H:i:s"),
23087                        'card_company' => $cardCompany,
23088                        'payment_plan_id' => $paymentPlanId,
23089                        'membership_type_index' => $membershipStatusIndex
23090                    ),
23091                    array(
23092                        'PaymentReceivable.user_id' => $userId,
23093                        'PaymentReceivable.status' => 0,
23094                        'PaymentReceivable.payment_element_type' => 1,
23095                        'PaymentReceivable.created <=' => date("Y-m-d H:i:s")
23096                    )
23097                );
23098            }
23099
23100            // if has appreciation receivable payment
23101            if ($appreciationReceivable > 0) {
23102                // set payment id
23103                $data["payment_id"] = $paymentId;
23104                //reset payment data
23105                $paymentData = array();
23106
23107                // set variables
23108                $paymentData = array(
23109                    'user_id' => $userId,
23110                    'amount' => $appreciationReceivable,
23111                    'status' => 1,
23112                    'type_id' => 1,
23113                    'reference_id' => $userId,
23114                    'card_company' => $cardCompany,
23115                    'param1' => json_encode($data),
23116                    'form_type' => Configure::read('appreciation_data.payment_form_type'),
23117                    'ordd' => $paymentHash,
23118                    'currency_code' => $currencyCode,
23119                    'transaction_code' => $paymentHash,
23120                    'price_id' => $priceId,
23121                    'payment_id' => $paymentPlanId,
23122                    'payment_type' => $paymentType,
23123                    'discounted_amount' => $discountedAmount
23124                );
23125
23126                // create new payment
23127                $this->Payment->clear();
23128                $this->Payment->create();
23129                $this->Payment->set($paymentData);
23130                $this->Payment->validate = array();
23131
23132                if (!$this->Payment->save()) {
23133                    $this->log(__METHOD__ . ' Failed to save appreciation receivable payment data for receivable.' . json_encode($paymentData), $logFileName);
23134                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data for receivable.', $paymentData);
23135                    $dataSource->rollback();
23136                    return false;
23137                }
23138                //update/add user`s settlement amount
23139                $this->User->updateUserPayments($paymentData);
23140                // set payment_id
23141                $appreciationPaymentId = $this->Payment->id;
23142
23143                // set live lesson payment receivable statuses to 2 - received
23144                $this->PaymentReceivable->updateReceivableReservationPayment(
23145                    $userId,
23146                    array(
23147                        'status' => 2,
23148                        'payment_id' => $appreciationPaymentId,
23149                        'payment_collection_date' => date("Y-m-d H:i:s"),
23150                        'card_company' => $cardCompany,
23151                        'payment_plan_id' => $paymentPlanId,
23152                        'membership_type_index' => $membershipStatusIndex
23153                    ),
23154                    array(
23155                        'PaymentReceivable.user_id' => $userId,
23156                        'PaymentReceivable.status' => 0,
23157                        'PaymentReceivable.payment_element_type' => Configure::read('appreciation_data.payment_element_type'),
23158                        'PaymentReceivable.created <=' => date("Y-m-d H:i:s")
23159                    )
23160                );
23161            }
23162
23163            // if has live lesson receivable payment
23164            if ($liveLessonReceivable) {
23165                // set payment id
23166                $data["payment_id"] = $paymentId;
23167
23168                $paymentData = array(
23169                    'user_id' => $userId,
23170                    'amount' => $liveLessonReceivable,
23171                    'status' => 1,
23172                    'type_id' => 1,
23173                    'reference_id' => $userId,
23174                    'card_company' => $cardCompany,
23175                    'param1' => json_encode($data),
23176                    'form_type' => Configure::read('payment_live_lesson_receivable'),
23177                    'ordd' => $paymentHash,
23178                    'currency_code' => $currencyCode,
23179                    'transaction_code' => $paymentHash,
23180                    'price_id' => $priceId,
23181                    'payment_id' => $paymentPlanId,
23182                    'payment_type' => $paymentType,
23183                    'discounted_amount' => $discountedAmount
23184                );
23185
23186                // create new payment
23187                $this->Payment->clear();
23188                $this->Payment->create();
23189                $this->Payment->set($paymentData);
23190                $this->Payment->validate = array();
23191
23192                if (!$this->Payment->save()) {
23193                    $this->log(__METHOD__ . ' Failed to save payment data for receivable.' . json_encode($paymentData), $logFileName);
23194                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data for receivable.', $paymentData);
23195                    $dataSource->rollback();
23196                    return false;
23197                }
23198
23199                //update/add user`s settlement amount
23200                $this->User->updateUserPayments($paymentData);
23201                // set payment_id
23202                $liveLessonPaymentId = $this->Payment->id;
23203
23204                // set live lesson payment receivable statuses to 2 - received
23205                $this->PaymentReceivable->updateReceivableReservationPayment(
23206                    $userId,
23207                    array(
23208                        'status' => 2,
23209                        'payment_id' => $liveLessonPaymentId,
23210                        'payment_collection_date' => date("Y-m-d H:i:s"),
23211                        'card_company' => $cardCompany,
23212                        'payment_plan_id' => $paymentPlanId,
23213                        'membership_type_index' => $membershipStatusIndex
23214                    ),
23215                    array(
23216                        'PaymentReceivable.user_id' => $userId,
23217                        'PaymentReceivable.status' => 0,
23218                        'PaymentReceivable.payment_element_type' => Configure::read('payment_element_type.live'),
23219                        'PaymentReceivable.created <=' => date("Y-m-d H:i:s")
23220                    )
23221                );
23222            }            
23223
23224            // NC-7029: CHECK REFERRAL USER
23225            if ($formType == Configure::read('payment_credit_retry') && isset($data['discountedAmount'])) {
23226                $ruData = array(
23227                    'referee_id' => $userId,
23228                    'payment_plan_id' => $paymentPlanId,
23229                    'currency_code' => $currencyCode,
23230                    'logFileName' => $logFileName,
23231                    'form_type' => $formType
23232                );
23233
23234                $couponReferredData = $this->UsersReferral->checkReferredUser($ruData);
23235                if (isset($couponReferredData['error']) && $couponReferredData['error']) {
23236                    $this->log(__METHOD__ . ' Failed to update users referral event flg.' . json_encode($ruData), $logFileName);
23237                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update users referral event flg.', $ruData);
23238                    $dataSource->rollback();
23239                    return false;
23240                }
23241
23242
23243                $couponMailId = Configure::read('site_in_mail.coupon_mail_template_id');
23244
23245                // send coupon mail to referee
23246                if (isset($couponReferredData['sendMailToReferee']) && $couponReferredData['sendMailToReferee']) {
23247                    $refereeData = array(
23248                        'id' => $userId,
23249                        'email' => $userData['email'],
23250                        'native_language2' => $userData['native_language2'],
23251                        'hash' => $userData['hash'],
23252                        'refereeName' => $userData['nickname'],
23253                        'referrerName' => $couponReferredData['referrerName'],
23254                        'couponAmount' => $couponReferredData['refereeSaveAmount'],
23255                        'couponUpdatedTotal' => $couponReferredData['refereeUpdatedTotal']
23256                    );
23257
23258                    // send mail to referee
23259                    myMailer::sendTemplateMail($couponMailId, $userData['email'], $refereeData, array(), 'User');
23260                }
23261
23262                // send coupon mail to referer
23263                if (isset($couponReferredData['sendMailToReferer']) && $couponReferredData['sendMailToReferer']) {
23264                    $referrerData = array(
23265                        'id' => $couponReferredData['referrerId'],
23266                        'email' => $couponReferredData['referrerEmail'],
23267                        'native_language2' => $couponReferredData['nativeLanguage2'],
23268                        'hash' => $couponReferredData['referrerHash'],
23269                        'refereeName' => $userData['User']['nickname'],
23270                        'referrerName' => $couponReferredData['referrerName'],
23271                        'couponAmount' => $couponReferredData['refererSaveAmount'],
23272                        'couponUpdatedTotal' => $couponReferredData['refererUpdatedTotal']
23273                    );
23274
23275                    // send mail to referrer
23276                    myMailer::sendTemplateMail($couponMailId, $couponReferredData['referrerEmail'], $referrerData, array(), 'User');
23277                }
23278            }
23279
23280            $discountOption = isset($data['discountOption']) ? $data['discountOption'] : [];
23281            // if user plan has annual discount option
23282            if ($discountOption) {
23283                $contractStart = $formType != Configure::read('payment_credit_authentication') ? date('Y-m-d 00:00:00') : (isset($nextChargeDate) ? $nextChargeDate : $this->User->getFirstNextChargeDate());
23284                switch ($formType) {
23285                    case Configure::read('payment_credit_retry'):
23286                        $discountOption += [
23287                            'contract_start' => $contractStart,
23288                            'currency_code' => $currencyCode,
23289                            'payment_id' => $paymentId,
23290                            'dosh_settlement_status' => 1, // success
23291                            'form_type' => $formType
23292                        ];
23293
23294                        if (!$this->UserDiscountOptionsTerm->processMonthlyDiscountOption($discountOption)) {
23295                            $this->log(__METHOD__ . ' Failed to process monthly discount option. ' . json_encode($discountOption) . ' -- ' . json_encode($createOrderResult), $logFileName);
23296                            $dataSource->rollback();
23297                            return false;
23298                        }
23299                        break;
23300                    case Configure::read('payment_credit_force_charge'):
23301                        $doshStatus = $formType == Configure::read('payment_credit_authentication') ?
23302                            Configure::read('discount_option.dosh_status.subscription') :
23303                            Configure::read('discount_option.dosh_status.monthly_discount');
23304
23305                        // set data for user discount option term
23306                        $udotData = [
23307                            'userId' => $userId,
23308                            'discountOptionId' => $discountOption['discount_option_id'],
23309                            'discountOptionPriceId' => $discountOption['discount_option_price_id'],
23310                            'contractStart' => $contractStart,
23311                            'logFileName' => $logFileName,
23312                            'paymentId' => $paymentId,
23313                            'discountAmount' => $discountOption['amount'],
23314                            'doshEvent' => isset($discountOption['dosh_event']) ? $discountOption['dosh_event'] : Configure::read('discount_option.dosh_event.annual_discount'),
23315                            'currencyCode' => $currencyCode,
23316                            'doshStatus' => isset($discountOption['dosh_status']) ? $discountOption['dosh_status'] : $doshStatus,
23317                            'formType' => $formType
23318                        ];
23319
23320                        // create user discount option term
23321                        if (!$this->UserDiscountOptionsTerm->createTerm($udotData)) {
23322                            $this->log(__METHOD__ . ' Failed to create user discount option term. ' . json_encode($udotData) . ' -- ' . json_encode($createOrderResult), $logFileName);
23323                            $dataSource->rollback();
23324                            return false;
23325                        }
23326
23327                        $adoLogParams = [
23328                            'user_id' => $userId,
23329                            'platform' => $platform,
23330                            'status' => 1, // subscribe
23331                            'controller_name' => $this->request->params['controller'],
23332                            'action_name' => $this->request->params['action'],
23333                            'user_type' => 0, // normal user
23334                            'option_before' => '',
23335                            'option_after' => 1,
23336                            'option_before_name' => '',
23337                            'option_after_name' => 'Annual Discount Option',
23338                            'option_type' => 3, // annual discount option
23339                            'payment_plan_id' => $paymentPlanId
23340                        ];
23341
23342                        if (!$this->UserOptionChangeLog->saveOptionChangeLog($adoLogParams)) {
23343                            $this->log(__METHOD__ . ' Failed to update option change. ' . json_encode($adoLogParams) . ' -- ' . json_encode($createOrderResult), $logFileName);
23344                            $dataSource->rollback();
23345                            return false;
23346                        }
23347                        break;
23348                }
23349            }
23350
23351            $dataSource->commit();
23352
23353            // update payment transaction
23354            $this->updatePaymentTransaction(array(
23355                'id' => $ptId,
23356                'fields' => array(
23357                    'status' => 1, // success
23358                    'response_text' => array('paypal_result' => $paypalData)
23359                ),
23360                'logFileName' => $logFileName
23361            ));
23362
23363            $adjustParams = array(
23364                'formType' => $formType,
23365                'statusBefore' => isset($ptPaymentParams['statusBefore']) ? $ptPaymentParams['statusBefore'] : null,
23366                'userId' => $userId,
23367                'idfa' => $userData['idfa']
23368            );
23369            UserTable::sendEventToAdjust($adjustParams);
23370
23371            if ( //Amazon gift campaign
23372                in_array($formType, array($ftCardAuth, $ftForceCharge))
23373            ) {
23374                ClassRegistry::init('CampaignSettingTable')->amazonGift(array('user_id' => $userId, 'type' => 1));
23375            }
23376
23377            // Teacher Perks : Student re-enroll
23378            if ( $formType == Configure::read('payment_credit_force_charge')) {
23379                ClassRegistry::init('TeacherPerksAccount')->reEnroll(['user_id' => $userId]);
23380            }
23381
23382            //    NC-7644 Add code reward for re-enroolling with the campaign code
23383            $this->addCoinRewardForReenroll($userData);
23384
23385        
23386            // - NJ-18780 : add monthly coin for lite plan user 
23387            if (
23388                $formType == Configure::read('payment_lite_credit_paid') || 
23389                ($formType == Configure::read('payment_credit_retry') && $isLitePlanUser)
23390            ) {
23391                $this->liteUserAddCoinRewardForReenroll($userData);
23392            }
23393            
23394            return true;
23395        } else {
23396            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Paypal process payment - failed to create order', $paypalData, $createOrderResult);
23397        }
23398
23399        return false;
23400    }
23401    
23402    //    NC-7644 Add code reward for re-enroolling with the campaign code
23403    public function addCoinRewardForReenroll($userData = array()){
23404        $this->autoRender = false;
23405        /* 
23406            NC-7644  
23407            get the count of user deactivation enquate 
23408        */
23409        $deactivationEnquateCount = $this->UsersDeactivationEnquate->usersDeactivationEnquateCount($userData['id']);
23410        
23411        // NC-7644 user first_charge_date
23412        $firstChargeDatePlus7Days = date('Y-m-d H:i:s', strtotime($userData['first_charge_date'].'+ 7 days')); 
23413        $dateNow = date('Y-m-d H:i:s'); 
23414
23415        /*     NC-7644 get user membership type 
23416            NC-7644 ticket Need a return of `12` 12 => 'Free'
23417        */
23418        $userObj = new UserTable($userData);
23419        $userMembership = $userObj->getMembershipTypeIndex();
23420
23421        // NC-7644 get currency
23422        $userCurrencyCode = isset($userData['currency_code']) ? $userData['currency_code'] : Configure::read('default.user_currency');
23423
23424        // get the campaign `CC_RE10` unique memCached
23425        $mem = new myMemcached();
23426        $memKey = 'campaign_code_CC_RE10' . $userData['id'];
23427        $memKey2 = 're_enroll_cc_re10' . $userData['id'];
23428        $hasCampaignCode = $mem->get($memKey);
23429        $mem->delete($memKey);
23430        $mem->delete($memKey2);
23431        
23432        /*     get `CC_RE10` the campaign id 
23433            get the envi event id
23434        */
23435        $coinEnviEventId = Configure::read('campaign_config.coin_event_id.reenroll');
23436        $coinEventId = $coinEnviEventId[Configure::read('ENVIRONMENT')];
23437        
23438        // chect if has already this campaign event id to the coin boxes table
23439        $hasReceivedCoin = $this->CoinBox->checkUserFirstTimeReceivedRewardCoin($userData['id'], $coinEventId);
23440        
23441        $this->log(__METHOD__ ."sai_debug -> Add 500 Coin Reward for firstChargeDatePlus7Days: ".json_encode($firstChargeDatePlus7Days), "debug");
23442        $this->log(__METHOD__ ."sai_debug -> Add 500 Coin Reward for dateNow: ".json_encode($dateNow), "debug");
23443        $this->log(__METHOD__ ."sai_debug -> Add 500 Coin Reward for userCurrencyCode: ".json_encode($userCurrencyCode), "debug");
23444        $this->log(__METHOD__ ."sai_debug -> Add 500 Coin Reward for userMembership: ".json_encode($userMembership), "debug");
23445        $this->log(__METHOD__ ."sai_debug -> Add 500 Coin Reward for deactivationEnquateCount: ".json_encode($deactivationEnquateCount), "debug");
23446        $this->log(__METHOD__ ."sai_debug -> Add 500 Coin Reward for hasCampaignCode: ".json_encode($hasCampaignCode), "debug");
23447        $this->log(__METHOD__ ."sai_debug -> Add 500 Coin Reward for corporate_id: ".json_encode($userData['corporate_id']), "debug");
23448        $this->log(__METHOD__ ."sai_debug -> Add 500 Coin Reward for studysapuri_id: ".json_encode($userData['studysapuri_id']), "debug");
23449        $this->log(__METHOD__ ."sai_debug -> Add 500 Coin Reward for hasReceivedCoin: ".json_encode($hasReceivedCoin), "debug");
23450
23451
23452        $isLitePlanUser = in_array($userMembership, Configure::read('membership_type_lightplan')) ? true : false;
23453        
23454        if (
23455            $firstChargeDatePlus7Days < $dateNow                            // need expire 7 day trial
23456            // && $userCurrencyCode == Configure::read('currency_jpy')        // need to have a JPY currency : [NJ-37810] Change from JPY -> All Currencies 
23457            && $userMembership == 12                                        // need to have a  `Free` membership
23458            && $deactivationEnquateCount == 1                                // need to have only 1 user deactivation enquate
23459            && (isset($hasCampaignCode) && $hasCampaignCode)                // need have a campaign code `CC_RE10`
23460            && !$userData['corporate_id'] && !$userData['studysapuri_id']    // need not a user corporate or sapuri
23461            && !$hasReceivedCoin
23462            &&    !$isLitePlanUser                                         // user will recieved this once
23463        ) {
23464            
23465            // grant 500 coins for re-enrolling with 1 users_deactivation_enquates
23466            $coinReward = 500;
23467            
23468            // insert coin boxes
23469            ClassRegistry::init('CoinBox')->clear();
23470            $rewardParams = array(
23471                'status'         => 1,
23472                'user_id'         => $userData['id'],
23473                'coin_event_id'    => $coinEventId,
23474                'coin'             => $coinReward
23475            );
23476            $addCoinReward = ClassRegistry::init('CoinBox')->addCoinReward($rewardParams);
23477            $this->log(__METHOD__ ."sai_debug -> Add 500 Coin Reward for re-enroll: ".json_encode($addCoinReward), "debug");
23478            if (!$addCoinReward) {
23479                $this->log(__METHOD__ ."sai_debug -> unable to add coin reward data: ".json_encode($rewardParams), "debug");
23480            }
23481        }
23482        // NC-7644 end of code
23483    }
23484    
23485    private function paypalSaveBillingAgreement($data = array(), $userData = array()) {
23486        $logFileName = 'paypal_debug';
23487        $ret = array('success' => false);
23488
23489        $memKey = 'paypalBillingAgreementData_' . $userData['api_token'];
23490        // return false if memcache billing agreement data does not exist
23491        if (!$paypalData = $this->memcache->get($memKey)) {
23492            $this->log(__METHOD__ . ' Memcached billing agreement data does not exist. --> ' . json_encode($paypalData) . ' | data --> ' . json_encode($data) . ' | user data --> ' . json_encode($userData), $logFileName);
23493            return $ret;
23494        }
23495
23496        // set paypal data
23497        $ret['paypalData'] = $paypalData;
23498
23499        if (
23500            !isset($paypalData['accessTokenData']['access_token']) || 
23501            !isset($paypalData['finalizeBillingAgreementData']['id']) ||
23502            !isset($paypalData['finalizeBillingAgreementData']['payer']['payer_info']['payer_id']) ||
23503            !isset($paypalData['finalizeBillingAgreementData']['payer']['payer_info']['email'])
23504        ) {
23505            $this->log(__METHOD__ . ' Missing billing agreement param(s). --> ' . json_encode($paypalData), $logFileName);
23506            return $ret;
23507        }
23508
23509        $formType = $data['formType'];
23510        $accessToken = $paypalData['accessTokenData']['access_token'];
23511        $baId = $paypalData['finalizeBillingAgreementData']['id']; // billing agreement id
23512        $payerId = $paypalData['finalizeBillingAgreementData']['payer']['payer_info']['payer_id'];
23513        $payerEmail = $paypalData['finalizeBillingAgreementData']['payer']['payer_info']['email'];
23514        $userData['payment_plan_id'] = $data['paymentPlanData']['paymentPlanId'];
23515        $userData['price_id'] = $data['paymentPlanData']['priceId'];
23516        $userData['paymentAmount'] = 0;
23517
23518        // - NJ-18780 : change to correct form type 
23519        if (
23520            $formType != Configure::read('payment_credit_change') &&
23521            in_array($userData['payment_plan_id'], Configure::read('lite_payment_plans'))
23522        ) {
23523            $formType = myTools::getLitePlanUserFormType(Configure::read('payment_plans.light_plan_free'));
23524        }
23525
23526        // add if subscribe to annual discount option
23527        if (isset($data['discountOption'])) {
23528            $userData['discountOption'] = $data['discountOption'];
23529        }
23530
23531        // return false if failed to create payment transaction
23532        if (!$pt = $this->createPaymentTransaction($formType, $userData)) {
23533            $this->log(__METHOD__ .' Failed to save payment transaction. Params --> ' . json_encode($userData), $logFileName);
23534            return $ret;
23535        }
23536
23537        $paymentHash = $pt['payment_hash'];
23538        $ret['ptId'] = $ptId = $pt['id'];
23539        $userId = $userData['id'];
23540        $currencyCode = Configure::read('default.user_currency');
23541
23542        $this->User->openDBReplica();
23543        $user = $this->User->find('first', array(
23544            'conditions' => array('User.id' => $userId)
23545        ));
23546        $this->User->closeDBReplica();
23547        
23548        $currency_before = !is_null($user['User']['currency_code']) ? $user['User']['currency_code'] : $currencyCode;
23549        $plan_before = !is_null($user['User']['payment_plan_id']) ? $user['User']['payment_plan_id'] : $userData['payment_plan_id'];
23550        // load PayPal class
23551        if (!class_exists('PayPal')) {
23552            App::import('Lib', 'PayPal');
23553        }
23554
23555        $paypal = new PayPal();
23556
23557        $createOrderParams = array(
23558            'accessToken' => $accessToken,
23559            'paypalRequestId' => $ptId,
23560            'intent' => 'AUTHORIZE',
23561            'paymentHash' => $paymentHash,
23562            'userId' => $userId,
23563            'currencyCode' => $currencyCode,
23564            'amount' => 1,
23565            'billingAgreementId' => $baId
23566        );
23567
23568        // create order
23569        $orderResult = $paypal->createOrder($createOrderParams);
23570        $ret['paypalData']['create_order_data'] = $orderResult;
23571
23572        if (!isset($orderResult['status']) || (isset($orderResult['status']) && $orderResult['status'] !== 'COMPLETED')) {
23573            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Paypal save billing agreement - failed to create order', $paypalData, $createOrderParams);
23574            $this->log(__METHOD__ . ' Create order error. --> ' . json_encode($orderResult) . ' | params --> ' . json_encode($createOrderParams) . ' | paypal data --> ' . json_encode($paypalData), $logFileName);
23575            return $ret;
23576        }
23577
23578        $authorizationVoidParams = array(
23579            'accessToken' => $accessToken,
23580            'authorizationId' => $orderResult['purchase_units'][0]['payments']['authorizations'][0]['id']
23581        );
23582
23583        // void authorization
23584        // expected return empty if success
23585        $voidResult = $paypal->authorizationVoid($authorizationVoidParams);
23586        $ret['paypalData']['authorization_void_data'] = $voidResult; // expected empty
23587
23588        if (!empty($voidResult)) {
23589            $this->log(__METHOD__ . ' authorization void error. --> ' . json_encode($voidResult) . ' | params --> ' . json_encode($authorizationVoidParams) . ' | paypal data --> ' . json_encode($paypalData), $logFileName);
23590            return $ret;
23591        }
23592
23593        $cardCompany = Configure::read('card_company.paypal');
23594
23595        if ($formType == Configure::read('payment_credit_authentication')) {
23596            $param1 = "paypal reregister, payment transaction id: {$ptId}";
23597        } else {
23598            $param1 = "paypal change, payment transaction id: {$ptId}";
23599        }
23600
23601        // initialize transaction
23602        $dataSource = $this->User->getDataSource();
23603        $dataSource->begin();
23604
23605        $savePaymentArr = array(
23606            'user_id' => $userId,
23607            'amount' => 0,
23608            'status' => 1,
23609            'reference_id' => $userId,
23610            'payment_transaction_password' => $pt['password'],
23611            'card_company' => $cardCompany,
23612            'param1' => $param1,
23613            'form_type' => $formType,
23614            'ordd' => $paymentHash,
23615            'transaction_code' => $paymentHash,
23616            'currency_id' => Configure::read('default.settlement_currency_id'), // set currency id to jpy
23617            'currency_code' => $currencyCode,
23618            'payment_id' => $userData['payment_plan_id'],
23619            'price_id' => $userData['price_id'],
23620            'payment_type' => Configure::read('payment_types.payment_plan'),
23621            'discounted_amount' => isset($userData['discounted_amount']) ? $userData['discounted_amount'] : 0
23622        );
23623
23624        // create new payment
23625        $this->Payment->clear();
23626        $this->Payment->create();
23627        $this->Payment->set($savePaymentArr);
23628        if (!$this->Payment->save()) {
23629            $this->log(__METHOD__ . ' Failed to save payment data. --> ' . json_encode($savePaymentArr) . ' | paypal data --> ' . json_encode($paypalData), $logFileName);
23630            $dataSource->rollback();
23631            return $ret;
23632        }
23633
23634        // set payment_id
23635        $paymentSaveID = $this->Payment->id;
23636
23637        //update/add user`s settlement amount
23638        $this->User->updateUserPayments($savePaymentArr);
23639
23640        $dateNow = date('Y-m-d H:i:s');
23641        $saveUserArr = array(
23642            'status' => 1,
23643            'modified' => $dateNow,
23644            'fail_flg' => 0,
23645            'charge_flg' => 1,
23646            'counseling_attended_flg' => 0,
23647            'card_company' => $cardCompany,
23648            'hash16' => $userId,
23649            'last_charge_date' => $dateNow,
23650            'paypal_billing_agreement_id' => $baId,
23651            'paypal_payer_id' => $payerId,
23652            'paypal_payer_email' => $payerEmail,
23653            'payment_plan_id' => $userData['payment_plan_id'],
23654            'price_id' => $userData['price_id'],
23655            'card_expiration_date' => null
23656        );
23657
23658
23659        // NJ-1562 - appreciation on
23660        if( $userData['payment_plan_id'] && in_array( $userData['payment_plan_id'], Configure::read('appreciation.payment_plan_id') ) ) {
23661            $saveUserArr['allow_appreciation_flg'] = 1; // on
23662            //NJ-7874 Turn Off appreciation settings for Family Plan (Default)
23663            if (in_array($userData['payment_plan_id'], Configure::read('appreciation.can_coin_purchase_check')) ) {
23664                $saveUserArr['allow_appreciation_flg'] = 0;
23665                $saveUserArr['show_appreciation_flg'] = 0;
23666                $saveUserArr['tip_max_amount'] = null;
23667            } else {
23668                $userBirthday  = $userData['User']['birthday'] ?? $userData['birthday'];
23669                $userAge = UserTable::getStudentAge($userBirthday);
23670                $userAge = $userAge ? (int) $userAge : null;
23671
23672                //default show appreciation flg
23673                $showAppreciationFlg = 0;
23674
23675                //change the show appreciation flg if no birthday set or 18 and above            
23676                if (!$userAge || $userAge >= 18) {
23677                    $showAppreciationFlg = 1;
23678                }
23679
23680                //set the show appreciation show
23681                $saveUserArr['show_appreciation_flg'] = $showAppreciationFlg; // set
23682            }
23683        }
23684
23685        $nextChargeDate = $this->User->getFirstNextChargeDate();
23686        if (
23687            $formType == Configure::read('payment_credit_authentication') || 
23688            $formType == Configure::read('payment_lite_credit_free') ||
23689            $formType == Configure::read('payment_credit_chocotto_free')
23690        ) {
23691            $saveUserArr['next_charge_date'] = $nextChargeDate;
23692        }
23693
23694        // NC-7779 : check if user has chivox monthly test taken for the current month, and monthly_speaking_attended_flg ON,
23695        // turn Off the flag if users has not yet taken the exam for the current month.
23696        // @TODO check query
23697        if (
23698            isset($userData['monthly_speaking_attended_flg']) && isset($userData['monthly_speaking_business_attended_flg']) &&
23699            ($userData['monthly_speaking_attended_flg'] == 1 || $userData['monthly_speaking_business_attended_flg'] == 1)
23700        ) {
23701
23702            // check chivox monthly
23703            $paymentPlanIdsForChivoxMonthly = Configure::read('chivox.monthly.user_payment_plan_cantake_exam');
23704            if (in_array($userData['payment_plan_id'], $paymentPlanIdsForChivoxMonthly)) {
23705
23706                // load model
23707                $this->loadModel("UsersChivoxMonthlyTest");
23708                $userTestMonthFlag = $this->UsersChivoxMonthlyTest->checkUserCurrentMonthExam(array('user_id' => $userId));
23709
23710                $monthlySpeakingAttendedFlg = Configure::read('chivox.test_data_test_type.daily'); // test_type daily speaking 0
23711                $monthlySpeakingBusinessAttendedFlg = Configure::read('chivox.test_data_test_type.business'); // test_type business 1
23712
23713                // if user hat not yet taken the exam for current month
23714                if (!in_array($monthlySpeakingAttendedFlg, $userTestMonthFlag)) {
23715                    $saveUserArr['monthly_speaking_attended_flg'] = 0;
23716                }
23717                if (!in_array($monthlySpeakingBusinessAttendedFlg, $userTestMonthFlag)) {
23718                    $saveUserArr['monthly_speaking_business_attended_flg'] = 0;
23719                }
23720            }
23721        }
23722
23723        $this->User->read(array_keys($saveUserArr), $userId);
23724        $this->User->set($saveUserArr);
23725        $this->User->validate = array();
23726        if (!$this->User->save()) {
23727            $this->log(__METHOD__ . ' Failed to update user data. --> ' . json_encode($saveUserArr) . ' | user id --> ' . $userId . ' | paypal data --> ' . json_encode($paypalData), $logFileName);
23728            $dataSource->rollback();
23729            return $ret;
23730        }
23731
23732
23733        // decode
23734        $ptPaymentParams = json_decode($pt['payment_params'], true);
23735
23736        if (
23737            $formType == Configure::read('payment_credit_authentication') || 
23738            $formType == Configure::read('payment_lite_credit_free') ||
23739            $formType == Configure::read('payment_credit_chocotto_free') 
23740        ) {
23741            $platform = $userData['platform'];
23742            // if plaftorm is empty
23743            if (!isset($platform)) {
23744                $platform = myTools::mobappDetectPlatform();
23745                if ($this->params->params['action'] == 'mobapp_paypal_credit_register_process') {
23746                    $platform = myTools::mobappDetectPlatform();
23747                } else {
23748                    $platform = Configure::read('platform.pclp');
23749                    if ($this->RequestHandler->isMobile()) {
23750                        $platform = Configure::read('platform.splp');
23751                    }
23752                }
23753
23754                // update platform
23755                $this->User->updateUserPlatform($userId, $platform);
23756            }
23757            $currentUser = $this->User->find('first', array(
23758                'fields' => array('User.parent_id', 'User.currency_code', 'User.payment_plan_id'),
23759                'conditions' => array('User.id' => $userId),
23760                'recursive' => -1
23761            ));
23762            $parentId = $currentUser['User']['parent_id'];
23763            $is_cron = 0;
23764            if (php_sapi_name() == 'cli'){
23765                $is_cron = 1;
23766            } 
23767               $currency_after = $currentUser['User']['currency_code'];
23768               $plan_after = $currentUser['User']['payment_plan_id'];
23769            $usclData = array(
23770                'user_id' => $userId,
23771                'platform' => $platform ?? '',
23772                'card_company_before' => '',
23773                'status_before' => $ptPaymentParams['statusBefore'],
23774                'status_after' => $ptPaymentParams['statusAfter'],
23775                'controller_name' => $this->request->params['controller'],
23776                'action_name' => $this->request->params['action'],
23777                'parent_id' => $parentId,
23778                'is_cron' => $is_cron,
23779                'currency_before' => $currency_before,
23780                'currency_after' => $currency_after,
23781                'payment_plan_id_before' => $plan_before,
23782                'payment_plan_id_after' => $plan_after
23783            );
23784
23785            // save user change membership status
23786            if (!$this->UserStatusChangeLog->saveLog($usclData)) {
23787                $this->log(__METHOD__ . ' Failed to save user status change log data. --> ' . json_encode($usclData) . ' | paypal data --> ' . json_encode($paypalData), $logFileName);
23788                $dataSource->rollback();
23789                return $ret;
23790            }
23791        }
23792
23793        // if parent user update children's card company
23794        if ($formType == Configure::read('payment_credit_change')) {
23795            $childList = $this->User->getChildId($userId);
23796            // check if user is parent
23797            if (!empty($childList)) {
23798                foreach ($childList as $childId) {
23799                    $this->User->clear();
23800                    $updateCCArr = array('card_company' => $cardCompany);
23801                    if (!$this->User->read(array_keys($updateCCArr), $childId)) {
23802                        $this->log(__METHOD__ . ' child id does not exist.  --> ' . json_encode($updateCCArr) . ' | parent id --> ' . $userId . ' | paypal data --> ' . json_encode($paypalData), $logFileName);
23803                        $dataSource->rollback();
23804                        return $ret;
23805                    }
23806
23807                    $this->User->set($updateCCArr);
23808                    if (!$this->User->save()) {
23809                        $this->log(__METHOD__ . ' failed to update child card company.   --> ' . json_encode($updateCCArr) . ' | parent id --> ' . $userId . ' | paypal data --> ' . json_encode($paypalData), $logFileName);
23810                        $dataSource->rollback();
23811                        return $ret;
23812                    }
23813                }
23814            }
23815        }
23816
23817        $annualDiscountOption = isset($userData['annualDiscountOption']) ? $userData['annualDiscountOption'] : []; 
23818        // if user plan has annual discount option
23819        if ($annualDiscountOption && $formType == Configure::read('payment_credit_authentication')) {
23820            // set data for user discount option term
23821            $udotData = [
23822                'userId' => $userId,
23823                'discountOptionId' => $annualDiscountOption['discount_option_id'],
23824                'discountOptionPriceId' => $annualDiscountOption['discount_option_price_id'],
23825                'contractStart' => isset($nextChargeDate) ? $nextChargeDate : $this->User->getFirstNextChargeDate(),
23826                'logFileName' => $logFileName,
23827                'paymentId' => $paymentSaveID,
23828                'discountAmount' => $annualDiscountOption['amount'],
23829                'doshEvent' => Configure::read('discount_option.dosh_event.annual_discount'),
23830                'currencyCode' => $currencyCode,
23831                'doshStatus' => Configure::read('discount_option.dosh_status.subscription')
23832            ];
23833
23834            // create user discount option term
23835            if (!$this->UserDiscountOptionsTerm->createTerm($udotData)) {
23836                $this->log(__METHOD__ . 'Failed to create user discount option term. ' . json_encode($udotData) . ' | paypal data --> ' . json_encode($paypalData), $logFileName);
23837                $dataSource->rollback();
23838                return $ret;
23839            }
23840
23841            $adoLogParams = [
23842                'user_id' => $userId,
23843                'platform' => $userData['platform'],
23844                'status' => 1, // subscribe
23845                'controller_name' => $this->request->params['controller'],
23846                'action_name' => $this->request->params['action'],
23847                'user_type' => 0, // normal user
23848                'option_before' => '',
23849                'option_after' => 1,
23850                'option_before_name' => '',
23851                'option_after_name' => 'Annual Discount Option',
23852                'option_type' => 3, // annual discount option
23853                'payment_plan_id' => $userData['payment_plan_id']
23854            ];
23855
23856            if (!$this->UserOptionChangeLog->saveOptionChangeLog($adoLogParams)) {
23857                $this->log(__METHOD__ . ' Failed to update option change. ' . json_encode($adoLogParams) . ' | paypal data --> ' . json_encode($paypalData), $logFileName);
23858                $dataSource->rollback();
23859                return $ret;
23860            }
23861        }
23862
23863        $ptUpdateParams = array(
23864            'id' => $pt['id'],
23865            'fields' => array(
23866                'status' => 1,
23867                'response_text' => $ret['paypalData']
23868            ),
23869            'logFileName' => $logFileName
23870        );
23871
23872        // update payment transaction
23873        if (!$this->PaymentTransaction->updateWPPaymentTransaction($ptUpdateParams)) {
23874            $this->log(__METHOD__ . ' Failed to update payment transaction. --> ' . json_encode($ptUpdateParams) . ' | paypal data --> ' . json_encode($paypalData), $logFileName);
23875            $dataSource->rollback();
23876            return $ret;
23877        }
23878
23879        $dataSource->commit();
23880
23881        if (isset($ptPaymentParams['userRegister']) && $ptPaymentParams['userRegister']) {
23882            UsersPointHistoryTable::checkDailyBonus($userId);
23883
23884            $receiveBonus = UsersPointTable::checkIfUserReceiveBonusUponRegister($userId);
23885            if (
23886                !$receiveBonus &&
23887                empty($userData['User']['complimentary_code']) &&
23888                !in_array(
23889                    $formType,
23890                    [
23891                        Configure::read('payment_credit_chocotto_free'),
23892                        Configure::read('payment_credit_chocotto_monthly_payment')
23893                    ]
23894                )
23895            ) {
23896                UsersPointTable::giveBonusCoins(['userId' => $userId, 'triggerNo' => 1]);
23897            } 
23898
23899            $this->User->clear();
23900            $_currentUser = $this->User->read(array('id','memo','payment_plan_id'), $userId);
23901            $_currentUserMemo = $_currentUser['User']['memo'];
23902
23903            # update user memo
23904            $_coins = Configure::read('credit.lite_plan_bonus_coin_authentication');
23905            $_dateNow = date('Y-m-d H:i:s');
23906            $_updateMemo =  "\n {$_dateNow} Light Plan Bonus: {$_coins}";
23907            $_updateMemo = $_updateMemo . "\n" . $_currentUserMemo;
23908
23909            // - update user memo 
23910            $this->User->clear();
23911            $memUpdateParams = array(
23912                'id' => $userId,
23913                'memo' => $_updateMemo
23914            );
23915            $this->User->set($memUpdateParams);
23916            $this->User->save();
23917        }
23918
23919        // campaign master trigger 5
23920        $this->retrial_confiscate_coins([
23921            'formType' => $formType,
23922            'paymentPlanId' => $userData['payment_plan_id'],
23923            'userId' => $userId
23924        ]);
23925
23926        // send event to adjust
23927        $adjustParams = array(
23928            'formType' => $formType,
23929            'statusBefore' => isset($ptPaymentParams['statusBefore']) ? $ptPaymentParams['statusBefore'] : null,
23930            'userId' => $userId,
23931            'idfa' => $userData['idfa']
23932        );
23933        UserTable::sendEventToAdjust($adjustParams);
23934
23935        return array('success' => true);
23936    }
23937
23938    private function setSupportPayPal($user = array()) {
23939        $supportPayPal = true;
23940        if (isset($user['corporate_id']) && $user['corporate_id']) {
23941            $supportPayPal = false;
23942        }
23943
23944        $memKey = '';
23945        switch ($this->params->params['action']) {
23946            case 'payment_credit_register':
23947                $memKey = 'creditReregisterPaymentGatewayType_';
23948                break;
23949            case 'payment_credit_retry':
23950                $memKey = 'creditRetryPaymentGatewayType_';
23951                break;
23952            case 'payment_credit_charge':
23953                $memKey = 'creditChargePaymentGatewayType_';
23954                break;
23955            case 'payment_credit_change':
23956                $memKey = 'creditChangePaymentGatewayType_';
23957                break;
23958            case 'mobapp_credit_register':
23959                $memKey = 'mobappCreditReregisterPaymentGatewayType_';
23960                break;
23961            case 'mobapp_credit_retry':
23962                $memKey = 'mobappCreditRetryPaymentGatewayType_';
23963                break;
23964            case 'mobapp_credit_charge':
23965                $memKey = 'mobappCreditChargePaymentGatewayType_';
23966                break;
23967            case 'mobapp_credit_change':
23968                $memKey = 'mobappCreditChangePaymentGatewayType_';
23969                break;
23970        }
23971
23972        if ($supportPayPal) {
23973            $this->set('paypalFlg', true);
23974        }
23975
23976        $isCardRegistered = (!empty($user['card_brand']) && !empty($user['card_number'])) ? true : false;
23977
23978        $paymentGatewayType = Configure::read('card_company.zeus');
23979        if (!empty($memKey)) {
23980            $memData = $this->memcache->get($memKey . $user['api_token']);
23981            $paymentGatewayType = $memData ? $memData : $paymentGatewayType;
23982        }
23983
23984        $this->set('supportPayPal', $supportPayPal);
23985        $this->set('isCardRegistered', $isCardRegistered);
23986        $this->set('paymentGatewayType', $paymentGatewayType);
23987        $this->set('zeusCC', Configure::read('card_company.zeus'));
23988        $this->set('paypalCC', Configure::read('card_company.paypal'));
23989        $this->setPaypalUser($user);
23990    }
23991    /**
23992     * @api {post} /payment/sms_questionnaire sms_questionnaire()
23993     * @apiName sms_questionnaire
23994     * @apiGroup Payment
23995     * @apiDescription Redirect to sms_questionnaire page
23996     * 
23997     * @apiSuccess {View} Redirect Redirect to sms_questionnaire page
23998     * 
23999     * @apiSuccessExample Success Response:
24000     * Redirects to {{ENV}}/account/sms_questionnaire
24001     * 
24002     * @apiSampleRequest off
24003     */
24004    public function sms_questionnaire() {
24005        $data = array(
24006            'origin_url' => '/payment/payment_credit_register',
24007            'success_url' => '/payment/payment_credit_register'
24008        );        
24009        $this->Session->write($data);
24010        return $this->redirect('/account/sms_questionnaire');
24011    }
24012
24013    private function restrictForTrialNotConducted($userData, $urlParams) {
24014        $user = new UserTable($userData);
24015        $membershipTypeIndex = $user->getMembershipTypeIndex();
24016        // no free trial for corporate individual users
24017        if ($membershipTypeIndex == 13 && empty($user->corporate_id) && myTools::isDateEmpty($user->first_charge_date)) {
24018            return $this->redirect(myTools::getUrl() . '/mobapp/plan/trial'.$urlParams);
24019        }
24020    }
24021
24022    public function zeuspayGetChallenge() {
24023        $this->autoLayout = false;
24024        $this->autoRender = false;
24025        
24026        // - get user data
24027        $data = $this->request->data;
24028        $data['corpIndiUser'] ??= '';
24029
24030        if(!empty($data['userApiToken'])) {
24031            $this->User->openDBReplica();
24032            $appUserData = $this->User->find('first', array(
24033                'fields' => array(
24034                    'User.id',
24035                    'User.status',
24036                ),
24037                'conditions' => array('User.api_token' => $data['userApiToken']),
24038                'recursive' => -1,
24039            ));
24040            $this->User->closeDBReplica();
24041
24042            if ($appUserData) {
24043                $this->isWithdrawn = (isset($appUserData['User']['status']) && $appUserData['User']['status'] == 9) ? true : $this->isWithdrawn;
24044            }
24045        }
24046
24047        $this->log('NJ-61937 - Blocking the Payment/zeuspayGetChallenge');
24048        $appVersion = isset($data['appVersion']) && !empty($data['appVersion']) ? $data['appVersion'] : 0;
24049        $deviceType = isset($data['deviceType']) && !empty($data['deviceType']) ? $data['deviceType'] : 0;
24050        if ($this->IpBlock->blocked() || $this->isWithdrawn) {
24051            if(!empty($appVersion) && !empty($deviceType)) {
24052                if (in_array($deviceType, [1,2,3])) {
24053                    $appVersionCompare = version_compare($appVersion, Configure::read('ip_block_app_version')[$deviceType], '<');
24054                    if (!$appVersionCompare) {
24055
24056                        $response = array(
24057                            'status' => 'blocked',
24058                            'isblocked' => 1,
24059                            'redirect_url_mobapp' => 'nativecamp://view/is_blocked',
24060                        );
24061
24062                        return json_encode($response);
24063                    }
24064                }
24065            } else if(empty($data['userApiToken'])) {
24066                $response = array(
24067                    'status' => 'blocked',
24068                    'isblocked' => 1,
24069                    'redirect_url' => myTools::getUrl()
24070                );
24071                $this->Auth->logout();
24072                if ($this->Session->read('check-step2')) {
24073                    $this->Session->delete('check-step2');
24074                }    
24075        
24076                if ($this->Session->read('check-step1')) {
24077                    $this->Session->delete('check-step1');
24078                }
24079                return json_encode($response);
24080            }
24081        }
24082
24083        $this->log('[ZeusJhayr] challenge data --> ' . json_encode($data), 'debug');
24084        // - if has recaptcha
24085        if (isset($data['g-recaptcha-response'])) {
24086            if (empty($data['g-recaptcha-response']) || !$data['g-recaptcha-response']) {
24087                $message = 'reCAPTCHA failed : error code 03';
24088                $this->Session->setFlash($message, '', array(), 'flashfailcaptcha');
24089                return 'captcha_error';
24090            }
24091        }
24092
24093        $originalAmount = isset($data['ZPaymentFullLogs']['money']) ? $data['ZPaymentFullLogs']['money'] : 0;
24094        $zFormType = isset($data['z_payment_form_type']) ? $data['z_payment_form_type'] : '';
24095        $studyAbroadFlg = $zFormType == Configure::read('payment_study_abroad') ? true : false;
24096
24097        // NJ-28462 Create Payment Transaction Corp Individual
24098        if( $data['corpIndiUser'] && !$studyAbroadFlg) {
24099            $corpIndiPT = $this->createCorporateIndividualPayment($data);
24100            $data['ZPaymentFullLogs']['paymentHash'] = $corpIndiPT['paymentHash'];
24101            $data['ZPaymentFullLogs']['money'] = $corpIndiPT['paymentAmount'];
24102        }
24103
24104        // corporate data
24105        $corporateId = $this->Session->read('corporateCompanyID');
24106        $rUserId = $corporateId;
24107        if (!empty($corporateId) && !$studyAbroadFlg){
24108            $corporateData = $this->Corporate->find("first",array(
24109                    "conditions" => array( "Corporate.id" => $corporateId),
24110                    "fields" => array("Corporate.email","Corporate.name"),
24111                    "recursive" => -1,
24112                )
24113            );
24114            $pData = array(
24115                'clientIp' => Configure::read('ZEUS_clientip'), # client ip
24116                'cardNumber' => $data['zeus_token_card_number'], # card number
24117                'expyy' => !empty($data['zeus_token_card_expires_year']) ? $data['zeus_token_card_expires_year'] : "0", # expired year
24118                'expmm' => !empty($data['zeus_token_card_expires_month']) ? $data['zeus_token_card_expires_month'] : "0", # expired month
24119                'telNo' => Configure::read('credit.default_telno'), # telephone number
24120                'email' => $corporateData['Corporate']['email'], # email
24121                'username' => mb_strtoupper($corporateData['Corporate']['name']), # username
24122                'sendId' => 'cz' . $corporateId, # id
24123                'money' => isset($data['ZPaymentFullLogs']['money']) ? (int)$data['ZPaymentFullLogs']['money'] : 0, # money
24124                'tokenKey' => $data["ZPaymentFullLogs"]['zeusTokenValue'],
24125                'paymentHash' => $data["ZPaymentFullLogs"]['paymentHash']
24126            );
24127        } else {
24128            $getData = $this->request->query;
24129            $userId = isset($data['userID']) && !empty($data['userID']) ? $data['userID'] : $this->Session->read('register_user_id');
24130
24131            $userToken = isset($data['userApiToken']) ? $data['userApiToken'] : '';
24132            $appVersion = isset($data['appVersion']) ? $data['appVersion'] : '';
24133            $deviceType = isset($data['deviceType']) ? $data['deviceType'] : '';
24134
24135            if (!empty($userToken)) {
24136                $condition = array('User.api_token' => $userToken);
24137            } else {
24138                $condition = array('User.id' => $userId);
24139            }
24140
24141            // - get user data
24142            $userData = $this->User->getUserDataUsingMasterDb(
24143                'first',
24144                $condition,
24145                array(
24146                    'User.email',
24147                    'User.id',
24148                    'User.parent_id',
24149                    'User.charge_flg',
24150                    'User.corporate_id',
24151                    'User.complimentary_code',
24152                    'User.currency_code',
24153                    'User.payment_plan_id',
24154                    'User.price_id',
24155                    'User.api_token',
24156                    'User.hash16',
24157                    'User.status',
24158                    'User.fail_flg',
24159                    'User.double_check_flg',
24160                    'User.phone_number',
24161                    'User.country_code',
24162                    'User.idfa',
24163                    'User.memo'
24164                )
24165            );
24166            $userCountryCode = $this->CountryCode->find('first', array(
24167                'conditions' => array(
24168                    'CountryCode.code' => $userData['User']['country_code']
24169                ),
24170                'recursive' => -1
24171            ));
24172            $userPayment = $this->Payment->find('all', [
24173                'conditions' => ['Payment.user_id' => $userData['User']['id']],
24174                'fields' => ['Payment.id'],
24175                'recursive' => -1 
24176            ]);
24177            $lastModifiedDate = date('YmdHis');
24178            $blockResult = $this->ZeusAccountBlock->processBlock($data);
24179            if (!empty($blockResult['status'])) {
24180                $requestParams = array(
24181                    'controller_origin' => $this->request->params['controller'],
24182                    'action_origin' => $this->request->params['action']
24183                );
24184                $userIdfaKey = !empty($userData['User']['idfa']) ? $userData['User']['idfa'] : null;
24185                $mobappUrlParam = '';
24186                if (!empty($userData['User']['idfa'])) {
24187                    $userIdfaKey = $userData['User']['idfa'];
24188                    if ($homeIdfaKey =  $this->memcache->get($userIdfaKey)) {
24189                        $mobappHomeParam = http_build_query($homeIdfaKey);
24190                        $mobappUrlParam = "/mobapp/home?is_block=1&{$mobappHomeParam}";
24191                    }
24192                }
24193                $this->User->forceWithdrawal($userData, $lastModifiedDate,$requestParams, $blockResult['id'], 0);
24194
24195                $redirect_url_mobapp = myTools::getUrl() . $mobappUrlParam;
24196
24197                if(!empty($appVersion) && !empty($deviceType)) {
24198                    if (in_array($deviceType, [1,2,3])) {
24199                        $appVersionCompare = version_compare($appVersion, Configure::read('ip_block_app_version')[$deviceType], '<');
24200                        if (!$appVersionCompare) {
24201                            $redirect_url_mobapp = 'nativecamp://view/is_blocked';
24202                        }
24203                    }
24204                }
24205
24206                $response = array(
24207                    'status' => 'blocked',
24208                    'isblocked' => 1,
24209                    'redirect_url' => myTools::getUrl(),
24210                    'redirect_url_mobapp' => $redirect_url_mobapp,
24211                    'data' => $blockResult
24212                );
24213                $this->Auth->logout();
24214                if ($this->Session->read('check-step2')) {
24215                    $this->Session->delete('check-step2');
24216                }    
24217        
24218                if ($this->Session->read('check-step1')) {
24219                    $this->Session->delete('check-step1');
24220                }
24221                return json_encode($response);
24222            } 
24223            // - validate user membership type
24224            $userInfo = new UserTable($userData['User']);
24225            $memberindex = $userInfo->getMembershipTypeIndex();
24226            if (
24227                isset($data['z_payment_form_type']) &&
24228                $data['z_payment_form_type'] == Configure::read("payment_credit_retry") && // retry form
24229                $memberindex == 1 // premium user
24230            ) {
24231                // - redirect to mypage 
24232                return $this->redirect('/');
24233            }
24234
24235            # lite plan 
24236            if (
24237                isset($data['ZPaymentFullLogs']['payment_plan_type']) && 
24238                in_array(
24239                    $data['ZPaymentFullLogs']['payment_plan_type'],
24240                    [
24241                        Configure::read('register_plan_types.light'),
24242                        Configure::read('register_plan_types.light_with_zero_student_discount_option')
24243                    ]
24244                )
24245            ) {
24246                $discountOption = [];
24247                if ($data['ZPaymentFullLogs']['payment_plan_type'] == Configure::read('register_plan_types.light_with_zero_student_discount_option')) {
24248                    $zeroStudentDocument = isset($_FILES['zero_student_discount_application_documents_file']) ? $_FILES['zero_student_discount_application_documents_file'] : null;
24249                    // - redirect to mypage if uploaded docs is empty
24250                    if (empty($zeroStudentDocument)) {
24251                        return $this->redirect('/');
24252                    }
24253
24254                    // get discount option data
24255                    $discountOption = $this->DiscountOptionsPrice->getPaymentData([
24256                        'currencyCode' => Configure::read('currency_jpy'),
24257                        'discountOptionId' => Configure::read('discount_option.zero_student.plan_id')
24258                    ]);
24259
24260                    // redirect to mypage if discount option does not exist or is not enabled
24261                    if (!$discountOption) {
24262                        return $this->redirect('/');
24263                    }
24264
24265                    $discountOption += [
24266                        'dosh_event' => Configure::read('discount_option.dosh_event.student_discount'),
24267                        'dosh_status' => Configure::read('discount_option.dosh_status.monthly_discount'),
24268                        'option_after_name' => 'Zero Student Discount Option',
24269                        'option_type' => 4
24270                    ];
24271
24272                    $moveUploadedFile = StudentDiscountApplicationFormTable::moveUploadedFile([
24273                        'folder' => 'img/uploads',
24274                        'formData' => $zeroStudentDocument
24275                    ]);
24276
24277                    // redirect to mypage if failed transfer the uploaded file
24278                    if (!$moveUploadedFile) {
24279                        return $this->redirect('/');
24280                    }
24281
24282                    $uploadedData = [
24283                        'source' => $moveUploadedFile['source'],
24284                        'key' => $moveUploadedFile['key'],
24285                        'uploader_type' => 39, // proof of document
24286                        'uploader_id' => $userId,
24287                        'file' => $moveUploadedFile['file']
24288                    ];
24289
24290                    // upload file
24291                    $uploadFileSuccess = $this->FileStorage->uploadFile($uploadedData);
24292                    if (!$uploadFileSuccess) {
24293                        return $this->redirect('/');
24294                    }
24295
24296                    $discountOption['application_form_app_image_url'] = $uploadFileSuccess['FileStorage']['url'];
24297
24298                    
24299                }
24300
24301                $form_type = isset($data['z_payment_form_type']) ? $data['z_payment_form_type'] : 0;
24302
24303                # no need to change the hash for retry and change form type
24304                if (
24305                    $form_type != Configure::read("payment_credit_retry") && 
24306                    (!isset($data['zeus_change_card']) || !$data['zeus_change_card'])
24307                ) {
24308                    # check  if lite plan is new register
24309                    $isLitePlanNewRegister = isset($data['zeus_cred_card_register']) ? true : false; 
24310
24311                    $lptParams = [
24312                        'userId' => $userData['User']['id'],
24313                        'formType' => $form_type,
24314                        'isNewRegister' => $isLitePlanNewRegister,
24315                        'studentDiscountOptionData' => $discountOption
24316                    ];
24317
24318                    # create a lite plan payment transaction 
24319                    $litePlanPT = $this->createLitePlanTransaction($lptParams);
24320
24321                    if ($litePlanPT) {
24322                        $data['ZPaymentFullLogs']['paymentHash'] = $litePlanPT['payment_hash'];
24323                        $data['ZPaymentFullLogs']['money'] = $litePlanPT['payment_monthly_amount'];
24324                    }
24325                }
24326
24327            //- chocotto plan
24328            } elseif (
24329                isset($data['ZPaymentFullLogs']['payment_plan_type']) && 
24330                in_array(
24331                    $data['ZPaymentFullLogs']['payment_plan_type'],
24332                    [
24333                        Configure::read('register_plan_types.chocotto')
24334                    ]
24335                )
24336            ) {
24337                $form_type = isset($data['z_payment_form_type']) ? $data['z_payment_form_type'] : 0;
24338
24339                # no need to change the hash for retry and change form type
24340                if (
24341                    $form_type != Configure::read("payment_credit_retry") && 
24342                    (!isset($data['zeus_change_card']) || !$data['zeus_change_card'])
24343                ) {
24344                    # check  if chocotto plan is new register
24345                    $isChocottoPlanNewRegister = isset($data['zeus_cred_card_register']) ? true : false; 
24346
24347                    $chocottoParams = [
24348                        'userId' => $userData['User']['id'],
24349                        'formType' => $form_type,
24350                        'isNewRegister' => $isChocottoPlanNewRegister
24351                    ];
24352
24353                    # create a lite plan payment transaction 
24354                    $chocottoPlanPT = $this->createChocottoPlanTransaction($chocottoParams);
24355
24356                    if ($chocottoPlanPT) {
24357                        $data['ZPaymentFullLogs']['paymentHash'] = $chocottoPlanPT['payment_hash'];
24358                        $data['ZPaymentFullLogs']['money'] = $chocottoPlanPT['payment_monthly_amount'];
24359                    }
24360                }
24361
24362            // premium plan with annual discount option
24363            } elseif (isset($data['ZPaymentFullLogs']['payment_plan_type']) && $data['ZPaymentFullLogs']['payment_plan_type'] == Configure::read('register_plan_types.premium_with_annual_discount_option')) {
24364                // get annual discount plan data
24365                $annualDiscountOption = $this->DiscountOptionsPrice->getPaymentData(['currencyCode' => $userInfo->currency_code, 'discountOptionId' => Configure::read('discount_option.annual.plan_id')]);
24366
24367                // redirect to credit page if annual discount option does not exist or is not enabled
24368                if (!$annualDiscountOption) {
24369                    // - redirect to mypage 
24370                    return $this->redirect('/');
24371                }
24372
24373                if ($data['ZPaymentFullLogs']['money'] <= $annualDiscountOption['amount']) {
24374                    $data['ZPaymentFullLogs']['money'] = 0;
24375                } else {
24376                    $data['ZPaymentFullLogs']['money'] -= $annualDiscountOption['amount'];
24377                }
24378
24379                // set the default value for dosh_status
24380                $doshStatus = Configure::read('discount_option.dosh_status.monthly_discount');
24381
24382                // check if it came from card registeration form
24383                $isFromCardRegistration = isset($data['zeus_cred_card_register']) ? true : false;
24384                if($isFromCardRegistration) {
24385                    // update the dosh_status to subscription as it is still in the free trial period.
24386                    $doshStatus = Configure::read('discount_option.dosh_status.subscription');
24387                }
24388
24389                $annualDiscountOption += [
24390                    'dosh_event' => Configure::read('discount_option.dosh_event.annual_discount'),
24391                    'dosh_status' => $doshStatus,
24392                    'option_after_name' => 'Annual Discount Option',
24393                    'option_type' => 3,
24394                    'from3DSecure' => true
24395                ];
24396
24397                $this->PaymentTransaction->updatePaymentParams(array('paymentHash' => $data['ZPaymentFullLogs']['paymentHash'], 'updateData' => ['discountOption' => $annualDiscountOption]));
24398            }
24399            
24400            // NJ-32737 - apply coupon
24401            $couponData = $this->Session->read('apply_coupon_usage_data');
24402            if (
24403                isset($couponData['useCouponAmount']) && $couponData['useCouponAmount'] > 0 &&
24404                in_array($data['z_payment_form_type'], Configure::read('allow_coupon.settlement_form_type'))
24405            ) {
24406                if ($data['ZPaymentFullLogs']['money'] <= $couponData['useCouponAmount']) {
24407                    $data['ZPaymentFullLogs']['money'] = 0;
24408                } else {
24409                    $data['ZPaymentFullLogs']['money'] -= $couponData['useCouponAmount'];
24410                }
24411                $this->PaymentTransaction->updatePaymentParams(array(
24412                    'paymentHash' => $data['ZPaymentFullLogs']['paymentHash'], 
24413                    'updateData' => ['couponUseSettlement' => $couponData]
24414                ));
24415                
24416                $this->log($data['ZPaymentFullLogs'],'users_coupon');
24417            }
24418
24419            if ((!isset($data['zeus_change_card']) || !$data['zeus_change_card']) && (!isset($data['zeus_cred_card_register']) || !$data['zeus_cred_card_register'])) { 
24420                $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userData['User']['id']);
24421                $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userData['User']['id'], false, Configure::read('appreciation_data.payment_element_type') );
24422                $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userData['User']['id'], false, Configure::read('payment_element_type.live'));
24423
24424                //NJ-20741
24425                $memcache_receivable_data = $this->memcache->get('memcache_receivable_data' . $userData['User']['id']);
24426                $reservationCoinPrice = isset($memcache_receivable_data['receivable_reservation_data']['reservation_coin_price']) ? $memcache_receivable_data['receivable_reservation_data']['reservation_coin_price'] : 0;
24427                $individual_payment_card_empty = isset($memcache_receivable_data['receivable_reservation_data']['individual_payment_card_empty']) && $memcache_receivable_data['receivable_reservation_data']['individual_payment_card_empty'] == true;
24428
24429                // do not charge immediately if individual payment card is empty
24430                if ($individual_payment_card_empty == false) {
24431                    $receivablePayment += $reservationCoinPrice;
24432                }
24433
24434                // validate the value if it is numeric
24435                $data['ZPaymentFullLogs']['money'] = isset($data['ZPaymentFullLogs']['money']) && is_numeric($data['ZPaymentFullLogs']['money']) ? $data['ZPaymentFullLogs']['money'] : 0;
24436                $receivablePayment = is_numeric($receivablePayment) ? $receivablePayment : 0;
24437                $appreciationReceivable = is_numeric($appreciationReceivable) ? $appreciationReceivable : 0;
24438                $liveLessonReceivable = is_numeric($liveLessonReceivable) ? $liveLessonReceivable : 0;
24439                
24440                // monthly settlement + payment receivables
24441                $data['ZPaymentFullLogs']['money'] = $data['ZPaymentFullLogs']['money'] + $receivablePayment + $appreciationReceivable + $liveLessonReceivable;
24442            }
24443
24444            if (isset($data['zeus_change_card']) && $data['zeus_change_card']) { 
24445                $data['no_redirection'] = true;
24446                // get reserve payment receivable
24447                $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userData['User']['id']);
24448
24449                // get appreciation payment receivable
24450                $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userData['User']['id'], false, Configure::read('appreciation_data.payment_element_type'));
24451
24452                // get live lesson payment receivable
24453                $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userData['User']['id'], false, Configure::read('payment_element_type.live'));
24454
24455                // payment receivables added
24456                $data['ZPaymentFullLogs']['money'] = $receivablePayment + $appreciationReceivable + $liveLessonReceivable;
24457            
24458                //- create new transaction if has payment receivable
24459                if (
24460                    !empty($data['ZPaymentFullLogs']['money']) &&
24461                    $data['ZPaymentFullLogs']['money'] > 0
24462                ) {
24463                    //-update amount
24464                    $userData['User']['paymentAmount'] = $data['ZPaymentFullLogs']['money'];
24465
24466                    // flagging for updating corporate user receivables
24467                    if (isset($userData['User']['corporate_id']) && $userData['User']['corporate_id']) {
24468                        $userData['User']['updateCorporateReceivable'] = true;
24469                    }
24470
24471                    if ($pt = $this->createPaymentTransaction(Configure::read('payment_credit_change'), $userData['User'])) {
24472                        //-update payment hash
24473                        $data['ZPaymentFullLogs']['paymentHash'] = $pt['payment_hash'];
24474                    }
24475                }
24476            }
24477
24478            $paymentHash = isset($data["ZPaymentFullLogs"]['paymentHash']) ? $data["ZPaymentFullLogs"]['paymentHash'] : '';
24479
24480            // If event is credit retry/force settlement check if discounted
24481            if (isset($data['z_payment_form_type']) && in_array($data['z_payment_form_type'], array(
24482                Configure::read('payment_credit_retry'), 
24483                Configure::read('payment_credit_force_charge'))
24484            )) {
24485
24486                $updateData = array();
24487
24488                if ($data['z_payment_form_type'] == Configure::read('payment_credit_retry')) {
24489                    // get user active annual discount option
24490                    $annualDiscountOptionData = $this->UserDiscountOptionsTerm->getTerm([
24491                        'user_id' => $userInfo->id,
24492                        'discount_option_id' => Configure::read('discount_option.annual.plan_id'),
24493                        'status' => 1
24494                    ]);
24495
24496                    if ($annualDiscountOptionData) {
24497                        if ($annualDiscountOptionData['amount'] < $data['ZPaymentFullLogs']['money']) {
24498                            $data['ZPaymentFullLogs']['money'] -= $annualDiscountOptionData['amount'];
24499                        } else {
24500                            $data['ZPaymentFullLogs']['money'] = 0;
24501                        }
24502                    }
24503
24504                    $coupon = $this->UsersCouponV1->getCouponUseRequest(array(
24505                        'userId' => $userData['User']['id'],
24506                        'kbn' => Configure::read('coupon_kbn.monthly_settlement')
24507                    ));
24508
24509                    if ($coupon) {
24510                        $data['ZPaymentFullLogs']['money'] -= $coupon['amount'];
24511                        $updateData['monthlyDiscount'] = $coupon['amount'];
24512                        $updateData['discounted_amount'] = $coupon['amount'];
24513                        $updateData['monthly_grp_id'] =  $coupon['grp_id'];
24514                    }
24515                }
24516
24517                // NJ-58167: Updates the amount in payment_params to properly set data in payment details for retry/force charge.
24518                $updateData['paymentAmount'] = isset($data['ZPaymentFullLogs']['money']) ? (int)$data['ZPaymentFullLogs']['money'] : 0;
24519                $this->PaymentTransaction->updatePaymentParams([
24520                    'paymentHash' => $paymentHash, 
24521                    'updateData' => $updateData
24522                ]);
24523                
24524                // If 0 payment no kickback 
24525                // if ($data['ZPaymentFullLogs']['money'] <= 0) {
24526                //     $zeroPaymentParams = array(
24527                //         'paymentHash' => $data["ZPaymentFullLogs"]['paymentHash'],
24528                //         'userId' => $userData['User']['id'],
24529                //         'money' => $data['ZPaymentFullLogs']['money'],
24530                //         'cardCompany' => Configure::read('card_company.zeus'),
24531                //         'controllerName' => 'Payment',
24532                //         'actionName' => 'zeuspayGetChallenge',
24533                //         'logFileName' => 'card_retry'
24534                //     );
24535
24536                //     if ($data['z_payment_form_type'] == Configure::read('payment_credit_force_charge')) {
24537                //         $discountedAmount = isset($couponData['useCouponAmount']) ? $couponData['useCouponAmount'] : 0;
24538                //         // create new term for force charge
24539                //         if (isset($annualDiscountOption) && $annualDiscountOption) {
24540                //             $udotData = [
24541                //                 'userId' => $userData['User']['id'],
24542                //                 'discountOptionId' => $annualDiscountOption['discount_option_id'],
24543                //                 'discountOptionPriceId' => $annualDiscountOption['discount_option_price_id'],
24544                //                 'contractStart' => date('Y-m-d 00:00:00'),
24545                //                 'logFileName' => 'card_retry'
24546                //             ];
24547
24548                //             $zeroPaymentParams['zeroPayment3D'] = true;
24549
24550                //             // create user discount option term
24551                //             $this->UserDiscountOptionsTerm->createTerm($udotData);
24552
24553                //             // get newly created term
24554                //             $annualDiscountOptionData = $this->UserDiscountOptionsTerm->getTerm([
24555                //                 'user_id' => $userData['User']['id'],
24556                //                 'discount_option_id' => Configure::read('discount_option.annual.plan_id'),
24557                //                 'status' => 1
24558                //             ]);
24559
24560                //             // append discount term to payment transactions
24561                //             if ($annualDiscountOptionData) {
24562                //                 $annualDiscountOption += [
24563                //                     'user_id' => $userData['User']['id'],
24564                //                     'discount_option_term_id' => $annualDiscountOptionData['discount_option_term_id']
24565                //                 ];
24566                //                 $this->PaymentTransaction->updatePaymentParams(array('paymentHash' => $data['ZPaymentFullLogs']['paymentHash'], 'updateData' => ['discountOption' => $annualDiscountOption, 'discounted_amount' => $discountedAmount]));
24567                //             }
24568                //         } else {
24569                //             // append discounted amount
24570                //             $this->PaymentTransaction->updatePaymentParams(array('paymentHash' => $data['ZPaymentFullLogs']['paymentHash'], 'updateData' => ['discounted_amount' => $discountedAmount]));
24571                //         }
24572                //     }
24573
24574                //     $zeroPayment = $this->Payment->zeroPayment($zeroPaymentParams);
24575
24576                //     $xmlResponse = array();
24577
24578                //     if (isset($zeroPayment['success']) && $zeroPayment['success']) {
24579                //         // update old complimentary code active_flg to 0
24580                //         if($userData['User']['complimentary_code']){
24581                //             $this->CompCodeUsage->updateAll(
24582                //                 array (
24583                //                     'active_flg' => 0
24584                //                 ),
24585                //                 array ('user_id' => $userData['User']['id'],
24586                //                         'active_flg' => 1,
24587                //                         'code' => $userData['User']['complimentary_code'])
24588                //             );
24589                //         }
24590
24591                //         $xmlResponse['result']['status'] = 'success';
24592                //         $xmlResponse['zero_payment'] = true;
24593                //         $xmlResponse['challenge_status'] = 1;
24594                //         $xmlResponse['paymentHash'] = $data["ZPaymentFullLogs"]['paymentHash'];
24595                //         $xmlResponse['paymentAmount'] = $data['ZPaymentFullLogs']['money'];
24596                //     }
24597
24598                //     return json_encode($xmlResponse);
24599                // }
24600            }
24601
24602            $paymentHash = isset($data["ZPaymentFullLogs"]['paymentHash']) ? $data["ZPaymentFullLogs"]['paymentHash'] : '';
24603
24604            if (
24605                (!empty($data['zeus_cred_card_register']) && $data['zeus_cred_card_register'] == 1) || 
24606                (!empty($data['zeus_change_card']) && $data['zeus_change_card'] == 1)
24607            ) {
24608                if (empty($data['zeus_token_card_name'])) {
24609                    $this->log(__LINE__, __METHOD__, 'Cardholder Name is not present --> ' . json_encode($data), 'debug');
24610                    $this->Session->setFlash('Cardholder Name is not present', array("element" => "flashfail"));
24611                }
24612            
24613                if (empty($userData['User']['email'])) {
24614                    $this->log(__LINE__, __METHOD__, 'Email is not present --> ' . json_encode($data), 'debug');
24615                    $this->Session->setFlash('Email is not present', array("element" => "flashfail"));
24616                }
24617            }
24618
24619            if ($paymentHash) {
24620                // If retry is already on process don't allowed to process again until 1 min
24621                if ($this->memcache->get('zeus_credit_retry'.$paymentHash)) {
24622                    $xmlResponse = array('challenge_status' => 3);
24623                    return json_encode($xmlResponse);
24624                }
24625
24626                $this->memcache->set(array(
24627                    'key' => 'zeus_credit_retry'.$paymentHash,
24628                    'value' => true,
24629                    'expire' => 60 // 1 min
24630                ));
24631            }
24632
24633            $pData = array(
24634                'clientIp' => Configure::read('ZEUS_clientip'), # client ip
24635                'cardNumber' => $data['zeus_token_card_number'], # card number
24636                'expyy' => !empty($data['zeus_token_card_expires_year']) ? $data['zeus_token_card_expires_year'] : "0", # expired year
24637                'expmm' => !empty($data['zeus_token_card_expires_month']) ? $data['zeus_token_card_expires_month'] : "0", # expired month
24638                'telNo' => Configure::read('credit.default_telno'), # telephone number
24639                'email' => $userData['User']['email'], # email
24640                'username' => $data['zeus_token_card_name'], # username
24641                'phoneNumber' => !empty($userData['User']['phone_number']) ? $userData['User']['phone_number'] : null,
24642                'countryCode' => !empty($userCountryCode['CountryCode']['num']) ? $userCountryCode['CountryCode']['num'] : null,
24643                'sendId' => $userData['User']['id'], # id
24644                'money' => isset($data['ZPaymentFullLogs']['money']) ? (int)$data['ZPaymentFullLogs']['money'] : 0, # money
24645                'tokenKey' => $data["ZPaymentFullLogs"]['zeusTokenValue'],
24646                'paymentHash' => $data["ZPaymentFullLogs"]['paymentHash']
24647            );
24648
24649            $rUserId = $userData['User']['id'];            
24650        }
24651
24652        $moneyAmout = isset($data['ZPaymentFullLogs']['money']) ? (int)$data['ZPaymentFullLogs']['money'] : 0;
24653        
24654        // overwrite for study abroad; special payment
24655        if ($studyAbroadFlg) {
24656            $pData['money'] = $originalAmount;
24657        }
24658
24659        App::import('Helper', 'Xml');
24660
24661        // - validate user
24662        $checkUser = $this->checkUser(null, null, true);
24663        if(
24664            // - if paid user
24665            $checkUser == Configure::read('user.member_type_paid') &&
24666            
24667            // - if has money
24668            $moneyAmout != 0 &&
24669            
24670            // - if not a complimentary user
24671            !($userData['User']['complimentary_code']) && 
24672
24673            // don't do redirection event
24674            empty($data['no_redirection'])
24675        ) {
24676            $form_type = isset($data['z_payment_form_type']) ? $data['z_payment_form_type'] : 0;
24677            // - redirect to complete page
24678            return $this->processRedirection($form_type);
24679        }
24680        
24681        // - set response
24682        $response = $this->ZCharge->create_charge_challenge(($pData));
24683        $xmlArray = Xml::toArray(Xml::build($response));
24684        $xmlResponse = isset($xmlArray['response']) ? $xmlArray['response'] : array();
24685
24686        $tmpPData = $pData;
24687        
24688        // - send debugging data
24689        unset($tmpPData['clientIp']);
24690        unset($tmpPData['cardNumber']);
24691        unset($tmpPData['email']);
24692        unset($tmpPData['expyy']);
24693        unset($tmpPData['expmm']);
24694        unset($tmpPData['phoneNumber']);
24695        if (isset($data["ZPaymentFullLogs"]['paymentHash']) && $data["ZPaymentFullLogs"]['paymentHash']) {
24696            $this->sendZeusResponseSlackMessage(array(
24697                'paymentHash' => $data["ZPaymentFullLogs"]['paymentHash'],
24698                'response' => $response,
24699                'userId' => !empty($corporateId) ? $corporateId : $userData['User']['id'],
24700                'userToken' => $userData['User']['api_token'],
24701                'action' => 'generating_zcharge_challenge -> ' . json_encode($tmpPData)
24702            ));
24703        }
24704
24705        // NJ-28462
24706        if( $data['corpIndiUser'] ) {
24707            $xmlResponse['paymentHash'] = $corpIndiPT['paymentHash'];
24708            $xmlResponse['paymentAmount'] = $corpIndiPT['paymentAmount'];
24709        }
24710
24711        // - add payment amount -> base on money that send to zeus
24712        if (!isset($xmlResponse['paymentAmount']) && isset($pData['money']) && $pData['money']) {
24713            $xmlResponse['paymentAmount'] = $pData['money'];
24714        }
24715
24716        // - ensure payment hash
24717        if (!isset($xmlResponse['paymentHash']) && isset($pData['paymentHash']) && $pData['paymentHash']) {
24718            $xmlResponse['paymentHash'] = $pData['paymentHash'];
24719        }
24720
24721        // if corporate
24722        if (!empty($corporateId)) {
24723            $xmlResponse['corporateId'] = $corporateId;
24724        }
24725
24726        // set zeus challenge flag
24727        if (isset($xmlResponse['result']['status']) && $xmlResponse['result']['status'] == 'success') {
24728            $userId = !empty($corporateId) ? $corporateId : $userData['User']['id'];
24729            
24730            // update old complimentary code active_flg to 0
24731            if($userData['User']['complimentary_code']){
24732                $this->CompCodeUsage->updateAll(
24733                    array (
24734                        'active_flg' => 0
24735                    ),
24736                    array ('user_id' => $userData['User']['id'],
24737                            'active_flg' => 1,
24738                            'code' => $userData['User']['complimentary_code'])
24739                );
24740            }
24741
24742            // - set flag
24743            $this->memcache->set(array(
24744                'key' => 'zeus3DSecureChallengeFlg_'.$userData['User']['id'],
24745                'value' => true,
24746                'expire' => 1800 // 30 minutes
24747            ));
24748            
24749            // - set 3ds formType
24750            $this->memcache->set(array(
24751                'key' => 'zeus_3dSecure_challenge_formType_'.$userData['User']['id'],
24752                'value' => isset($data['z_payment_form_type']) ? $data['z_payment_form_type'] : 0,
24753                'expire' => 1800 // 30 minutes
24754            ));
24755            
24756            // - set data
24757            $test = $this->memcache->set(array(
24758                'key' => 'zeus_3d_secure_pt_'.$userData['User']['id'],
24759                'value' => ($pData),
24760                'expire' => 1800 // 30 minutes
24761            ));
24762
24763            $this->memcache->set(array(
24764                'key' => 'register_or_charge_card_' . $userData['User']['id'],
24765                'value' => true,
24766                'expire' => 3600 // 1 hour
24767            ));
24768
24769            if (isset($data['fromPage']) && !empty($data['fromPage'])) {
24770                switch ($data['fromPage']) {
24771                    case 'coin':
24772                        $this->memcache->set(array(
24773                            'key' => 'common_corporate_transaction_coin_' . $userData['User']['id'],
24774                            'value' => true,
24775                            'expire' => 3600 // 1 hour
24776                        ));
24777                        break;
24778                    default:
24779                        $this->memcache->set(array(
24780                            'key' => 'common_corporate_transaction_' . $userData['User']['id'],
24781                            'value' => true,
24782                            'expire' => 3600 // 1 hour
24783                        ));
24784                        break;
24785                }
24786            }
24787        }
24788
24789        // // - debug
24790        // if (
24791        //     isset($xmlResponse["result"]["status"]) &&
24792        //     $xmlResponse["result"]["status"] == "success" &&
24793        //     (
24794        //         (
24795        //             Configure::read('ENVIRONMENT') == 'PRODUCTION' && 
24796        //             $data['zeus_token_card_number'] == '4834421406393969'
24797        //         )
24798        //         ||
24799        //         (
24800        //             Configure::read('ENVIRONMENT') == 'DEV' ||
24801        //             Configure::read('ENVIRONMENT') == 'STAGING'
24802        //         )
24803        //     )
24804        // ) {
24805        //     // - send slack
24806        //     $mySlack = new mySlack();
24807        //     $mySlack->channel = myTools::checkChannel("#fdci-nativecamp", "#fdci-nativecamp");
24808        //     $mySlack->link_names = true;
24809        //     $mySlack->allow_test_channel = true;
24810        //     $mySlack->token = "xoxp-392902820692-393103987059-747628176676-c8ea0bf485312302ce3788cc55100b30";
24811        //     $mySlack->text = "<!subteam^SNX2TCYAE|fdci-delivery>";
24812        //     $mySlack->text .= "```";
24813        //     $mySlack->text .= "environment: " . json_encode(Configure::read('ENVIRONMENT')) ."\n\n";
24814        //     $mySlack->text .= "user_id: " . json_encode($rUserId) ."\n\n";
24815        //     $mySlack->text .= "amount: " . json_encode($moneyAmout);
24816        //     $mySlack->text .= "```";
24817        //     $mySlack->sendSlack();
24818        // }
24819        
24820        // - return response
24821        return json_encode($xmlResponse);
24822    }
24823
24824    public function reportZeusChallengeResponse($data = array()) {
24825        $this->autoRender = false;
24826        $postData = $data ? $data : $this->request->data;
24827        $getData = $this->request->query;
24828        $userId = isset($getData['userID']) && !empty($getData['userID']) ? $getData['userID'] : $this->Session->read('register_user_id');
24829        $userToken = isset($getData['userApiToken']) ? $getData['userApiToken'] : '';
24830
24831        // - if invalid
24832        if (isset($postData['status']) && $postData['status'] != 'success' && isset($postData['PaRes']) && $postData['PaRes'] == 'N') {
24833            $this->log(__METHOD__ . ' PaRes failure: ' . $userId . ' | ' . $userToken . ' Data: ' . json_encode($postData), 'debug');
24834            return array(
24835                'success' => false,
24836                'errorMsg' => 'PaRes failure'
24837            );
24838        }
24839
24840        // - get user data
24841        $userData = $this->User->getUserDataUsingMasterDb(
24842            'first',
24843            array('User.id' => $userId),
24844            array(
24845                'User.email', 'User.id', 'User.corporate_id'
24846            )
24847        );
24848
24849        // - check mobapp token
24850        if (empty($userData) && !empty($userToken)){
24851            $userData = $this->User->getUserDataUsingMasterDb(
24852                'first',
24853                array('User.api_token' => $userToken),
24854                array(
24855                    'User.email', 'User.id', 'User.corporate_id'
24856                )
24857            );
24858        }
24859
24860        // - get userID
24861        $userId = isset($userData['User']['id']) ? $userData['User']['id'] : $userId;
24862
24863        // - get company data
24864        $corporateId = $this->Session->read('corporateCompanyID') ? $this->Session->read('corporateCompanyID') : ( !empty($getData['corporateId']) ? $getData['corporateId'] : '' );
24865        $corporateData = array();
24866        if (!empty($corporateId)){
24867            $corporateData = $this->Corporate->find("first",array(
24868                    "conditions" => array( "Corporate.id" => $corporateId),
24869                    "fields" => array("Corporate.email","Corporate.name"),
24870                    "recursive" => -1,
24871                )
24872            );
24873            $userId = $corporateId;
24874        }
24875
24876        // - if userID doe snot exist, return false
24877        if (!$userId) {
24878            $postData['PaRes'] = "N";
24879            echo json_encode($postData);
24880            $this->sendZeusResponseSlackMessage(array(
24881                'paymentHash' => @$getData['paymentHash'],
24882                'response' => "invalid user id supplied",
24883                'userId' => @$userId,
24884                'userToken' => $userToken,
24885                'action' => 'failed_to_get_user_information -> ' . json_encode($userId)
24886            ));
24887            return array(
24888                'success' => false,
24889                'errorMsg' => 'Invalid User Id supplied'
24890            );
24891        }
24892
24893        // - get paymentHash
24894        $paymentHash = "";
24895        if (isset($getData['paymentHash']) && $getData['paymentHash']) {
24896            $paymentHash = $getData['paymentHash'];
24897
24898        } else {
24899            $paymentHash = $this->memcache->get('zeus_3d_secure_pt_'.$userId);
24900            $getData['paymentHash'] = $paymentHash["paymentHash"];
24901
24902        }
24903
24904        // - if userID doe snot exist, return false
24905        if (!$paymentHash) {
24906            $postData['PaRes'] = "N";
24907            echo json_encode($postData);
24908            $this->sendZeusResponseSlackMessage(array(
24909                'paymentHash' => @$getData['paymentHash'],
24910                'response' => "invalid paymenthash supplied",
24911                'userId' => $userId,
24912                'userToken' => $userToken,
24913                'action' => 'no_payment_hash_provided'
24914            ));
24915            return array(
24916                'success' => false,
24917                'errorMsg' => 'Invalid Payment Hash supplied'
24918            );
24919        }
24920
24921        // - check if money amount  not exist
24922        if(!isset($getData['money']) || empty($getData['money'])) {
24923            $this->PaymentTransaction->openDBReplica();
24924            $getPtrans = $this->PaymentTransaction->find('first', array(
24925                'fields' => array('payment_params'),
24926                'conditions' => array('payment_hash' => $paymentHash),
24927                'recursive' => -1
24928            ));
24929            $this->PaymentTransaction->closeDBReplica();
24930
24931            // - if transaction does not exist
24932            if (!$getPtrans) {
24933                if (!empty($getData['corporateId'])) {
24934                    return true; // return true if corporate 
24935                }
24936                $postData['PaRes'] = "N";
24937                echo json_encode($postData);
24938                $this->sendZeusResponseSlackMessage(array(
24939                    'paymentHash' => @$getData['paymentHash'],
24940                    'response' => "no transaction found!",
24941                    'userId' => $userId,
24942                    'userToken' => $userToken,
24943                    'action' => 'failed_to_getPayment_transaction -> ' . json_encode($paymentHash)
24944                ));
24945                return array(
24946                    'success' => false,
24947                    'errorMsg' => 'No transaction found'
24948                );
24949            }
24950        }
24951        
24952        // - get transaction
24953        if (isset($getPtrans['PaymentTransaction']['payment_params'])) {
24954            $parseData = json_decode($getPtrans['PaymentTransaction']['payment_params'], true);
24955            $getData['money'] = $parseData['paymentAmount'];
24956        }
24957
24958        // - set response
24959        $response2 = $this->ZCharge->auth_charge_request([
24960            "auth_status" => $postData["MD"],
24961            "auth_code" => $postData["PaRes"]
24962        ]);
24963        $this->sendZeusResponseSlackMessage(array(
24964            'paymentHash' => $getData['paymentHash'],
24965            'response' => $response2,
24966            'userId' => $userId,
24967            'userToken' => $userToken,
24968            'action' => 'failed_to_authenticate_charged_request -> ' . json_encode($postData)
24969        ));
24970
24971        // - set response
24972        $response = $this->ZCharge->pay_charge_request([
24973            "auth_xid" => $postData["MD"]
24974        ]);
24975
24976        // - send slack message
24977        $slackMessageParams = array(
24978            'paymentHash' => $getData['paymentHash'],
24979            'response' => $response,
24980            'userId' => $userId,
24981            'userToken' => $userToken,
24982            'action' => 'failed_to_pay_charge_request -> ' . json_encode($getData)
24983        );
24984
24985        if (isset($response['payment_has_curl_error'])) {
24986            $slackMessageParams['error_msg'] = $response['payment_has_curl_error'];
24987            unset($response['payment_has_curl_error']);
24988            $slackMessageParams['response'] = json_encode($response);
24989        }
24990
24991        $this->sendZeusResponseSlackMessage($slackMessageParams);
24992
24993        if(empty($response) || !$response) {
24994            $response = array();
24995        }
24996        
24997        $xmlArray = Xml::toArray(Xml::build($response));
24998        $res = isset($xmlArray['response']) ? $xmlArray['response'] : array();
24999        $sendPoint = isset($res['addition_value']['sendpoint']) ? $res['addition_value']['sendpoint'] : '';
25000
25001        $zeuspay = array(
25002            'result' => isset($res['result']['status']) && $res['result']['status'] == 'success' ? 'OK' : 'NG',
25003            'money' => isset($getData['money']) && !empty($getData['money']) ? $getData['money'] : 0,
25004            'sendid' => isset($res['addition_value']['sendid']) && !empty($res['addition_value']['sendid']) ? $res['addition_value']['sendid'] : $userId,
25005            'sendpoint' => $sendPoint,
25006            'clientip' => Configure::read('ZEUS_clientip'),
25007            'ordd' => isset($res['order_number']) ? $res['order_number'] : '',
25008            'email' =>isset($corporateData['Corporate']['email']) ? $corporateData['Corporate']['email'] : $userData['User']['email'],
25009            'telno' => Configure::read('credit.default_telno'),
25010            'cardnumber' => isset($res['card']['number']['suffix']) ? $res['card']['number']['suffix'] : '',
25011            'cardbrand' => isset($res['addition_value']['ctype']) ? $res['addition_value']['ctype'] : '',
25012            'zeus3DSecureFlg' => 1
25013        );
25014        $tmpZeuspay = $zeuspay;
25015
25016        // - start debugging
25017        unset($tmpZeuspay['telno']);
25018        unset($tmpZeuspay['clientip']);
25019        unset($tmpZeuspay['email']);
25020        unset($tmpZeuspay['cardnumber']);
25021        $this->sendZeusResponseSlackMessage(array(
25022            'paymentHash' => $getData['paymentHash'],
25023            'response' => json_encode($zeuspay),
25024            'userId' => $userId,
25025            'userToken' => $userToken,
25026            'action' => 'triggering zeuspayments -> ' . json_encode($tmpZeuspay)
25027        ));
25028
25029        // NJ-20741
25030        if (
25031            isset($postData['PaRes']) && $postData['PaRes'] == "Y" && 
25032            isset($res['result']['status']) &&
25033            !empty($getData['zeusFormType']) &&
25034            ($getData['zeusFormType'] == 'corp_user_change_personal_card' || $getData['zeusFormType'] == 'student_discount_user_change_personal_card' || $getData['zeusFormType'] == 'common_corporate_card') &&
25035            !empty($getData['fromPC']) && $getData['fromPC'] == 1
25036        ) {
25037            $memcache_receivable_data = $this->memcache->get('memcache_receivable_data' . $userId);
25038            $reservationCoin = isset($memcache_receivable_data['receivable_reservation_data']['reservation_coin']) ? $memcache_receivable_data['receivable_reservation_data']['reservation_coin'] : 0;
25039            
25040            if (isset($res['result']['status']) && $res['result']['status'] == 'success') {
25041                $memcache_receivable_data['payment_status'] = 1;
25042                $reservationCoinPrice = isset($memcache_receivable_data['receivable_reservation_data']['reservation_coin_price']) ? $memcache_receivable_data['receivable_reservation_data']['reservation_coin_price'] : 0;
25043                
25044                if ((int)$reservationCoinPrice > 0) {
25045                    if (!isset($memcache_receivable_data)) $memcache_receivable_data = [];
25046                    $memcache_receivable_data['receivable_reservation'] = 1;
25047                    $memcache_receivable_data['paying_receivables'] = 1;
25048
25049                    $reserveData = isset($memcache_receivable_data['reserve_data']) ? $memcache_receivable_data['reserve_data'] : [];
25050                    if (!empty($reserveData)) {
25051
25052                        $reserveData['paying_receivables'] = 1;
25053                        $reserveData['card_company'] = Configure::read('card_company.zeus');
25054                        if (isset($memcache_receivable_data['actionType']) && $memcache_receivable_data['actionType'] == 'lesson_reservation') {
25055                            try {
25056                                $reserve_response = $this->LessonSchedule->addReserve($reserveData);
25057                            } catch (\Exception $e) {
25058                                $this->LessonSchedule->sendSlackExceptionReport([
25059                                    'error_message' => $e->getMessage(),
25060                                    'reserve_data' => $reserveData
25061                                ]);
25062                            }
25063                        } else if (isset($memcache_receivable_data['actionType']) && $memcache_receivable_data['actionType'] == 'reserved_confirmation') {
25064                            $reserve_response = $this->LessonSchedule->confirmReservationSchedule($reserveData);
25065                        }
25066
25067                        $memcache_receivable_data['reserve_response'] = isset($reserve_response) ? $reserve_response : null;
25068
25069                        if (
25070                            isset($reserve_response['lessonSchedId']) && $reserve_response['lessonSchedId'] > 0 &&
25071                            isset($reserve_response['res']) && $reserve_response['res'] == 1
25072                        ) {
25073                            $memcache_receivable_data['add_reserve_response'] = 1;
25074                            $memcache_receivable_data['lessonSchedId'] = $reserve_response['lessonSchedId'];
25075                        } else if (isset($reserve_response) && $reserve_response == '-1') {
25076                            $memcache_receivable_data['add_reserve_response'] = -1;
25077
25078                            if ($reservationCoin > 0) {
25079                                $_pointParams = array(
25080                                    'userId' => $userId,
25081                                    'point' => $reservationCoin,
25082                                    'kbn' => 2, // return coin
25083                                    'kbnType' => 1, // add coin
25084                                    'coinType' => 2, // // service coin
25085                                    'coinFailMessage' => Configure::read('coin.failed.reservation')
25086                                );
25087    
25088                                $this->UsersPoint->performPointTransaction($_pointParams);
25089                            }
25090                        }
25091
25092                        $individual_payment_card_empty = isset($memcache_receivable_data['receivable_reservation_data']['individual_payment_card_empty']) && $memcache_receivable_data['receivable_reservation_data']['individual_payment_card_empty'] == true;
25093                    }
25094                }
25095            } else {
25096                $memcache_receivable_data['paying_receivables'] = 1;
25097                $memcache_receivable_data['payment_status'] = 0;
25098            }
25099            
25100
25101            if (!empty($memcache_receivable_data)) {
25102                $this->memcache->set([
25103                    'key' => 'memcache_receivable_data' . $userId,
25104                    'value' => $memcache_receivable_data, 
25105                    'expire' => 1800 // 30 minutes
25106                ]);
25107            }
25108        }
25109        // end NJ-20741
25110
25111        // set zeus challenge paymenr result
25112        $this->memcache->set(array(
25113            'key' => 'zeus3DSecurePaymentSuccessFlg_' . $userId,
25114            'value' => $zeuspay['result'],
25115            'expire' => 1800 // 30 minutes
25116        ));
25117        
25118        $url = myTools::getUrl() . '/payment/zeuspay?'.http_build_query($zeuspay);
25119        $ch = curl_init($url);
25120        curl_setopt($ch, CURLOPT_URL, $url);
25121        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
25122        curl_setopt($ch, CURLOPT_HEADER,         false);
25123        curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36');
25124        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
25125        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
25126        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
25127        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
25128        $result = curl_exec($ch);
25129        curl_close($ch);
25130
25131        $this->Session->write('register_user_id', $userId);
25132            
25133        // - add response
25134        $tmpZeusPay = $zeuspay;
25135        unset($tmpZeuspay['email']);
25136        unset($tmpZeuspay['cardnumber']);
25137        unset($tmpZeuspay['telno']);
25138        $mySlack = new mySlack();
25139        $mySlack->allow_test_channel = true;
25140        $mySlack->channel = myTools::checkChannel("#nc-zeus-3ds-result", "#nc-zeus-3ds-result");
25141        $mySlack->username = "ZEUS CHALLENGE PARES RESPONSE";
25142        $mySlack->link_names = true;
25143        $mySlack->token = "xoxb-392902820692-6499139810404-RHHGc6Z5ZB9o2KkiGhzTTtlQ";
25144        $mySlack->text = "```";
25145        $mySlack->text .= "user_id || corporate id || token: " . json_encode($userId) ." OR " . $userToken . "\n\n";
25146        $mySlack->text .= "post_data: " . json_encode($postData) ."\n\n";
25147        $mySlack->text .= "get_data: " . json_encode($getData) ."\n\n";
25148        $mySlack->text .= "auth_response: " . json_encode($response2) ."\n\n";
25149        $mySlack->text .= "pay_response: " . json_encode($response) ."\n\n";
25150        $mySlack->text .= "zeuspay params: " . json_encode($tmpZeuspay) ."\n\n";
25151        $mySlack->text .= "zeuspay response: " . json_encode($result) ."\n\n";
25152        $mySlack->text .= "referrer: " . json_encode($_SERVER['HTTP_REFERER']) ."\n\n";
25153        $mySlack->text .= "user agent: " . json_encode(myTools::uAPlatformVersion($_SERVER['HTTP_USER_AGENT'])) ."\n\n";
25154        $mySlack->text .= "```";
25155        
25156        // - send slack
25157        if (!$mySlack->postMessage()) {
25158        }
25159
25160        if (!empty($memcache_receivable_data) && isset($memcache_receivable_data['receivable_reservation_data']['reservation_coin_price'])) {
25161            return array(
25162                'success' =>true,
25163                'memcache_receivable_data' => $memcache_receivable_data,
25164                'errorMsg' => ''
25165            );
25166        }
25167
25168        // - if zeuspay result is NG
25169        if ($zeuspay['result'] == 'NG' && !empty($userData['User']['corporate_id'])) {
25170            return array(
25171                'success' => false,
25172                'errorMsg' => 'NG_return from zeus'
25173            );
25174        }
25175        
25176        // - return
25177        return true;
25178    }
25179
25180    private function sendZeusResponseSlackMessage($params) {
25181        // - add response
25182        $mySlack = new mySlack();
25183        $mySlack->allow_test_channel = true;
25184        $mySlack->channel = myTools::checkChannel("#nc-zeus-3ds-result", "#nc-zeus-3ds-result");
25185        $mySlack->username = "ZEUS CHALLENGE RESPONSE";
25186        $mySlack->link_names = true;
25187        $mySlack->token = "xoxb-392902820692-6499139810404-RHHGc6Z5ZB9o2KkiGhzTTtlQ";
25188        $mySlack->text = "```";
25189        $mySlack->text .= "user_id || corporate id || token: " . $params['userId'] ." OR " . $params['userToken'] . "\n\n";
25190        $mySlack->text .= "payment_hash: " . $params['paymentHash'] ."\n\n";
25191        // $mySlack->text .= "response: " . $params['response'] ."\n\n";
25192        $mySlack->text .= "action: " . $params['action'] ."\n\n";
25193        if(isset($params['error_msg']) && $params['error_msg']) {
25194            $mySlack->text .= "error: " . $params['error_msg'] ."\n\n";
25195        }
25196        $mySlack->text .= "```";
25197        $mySlack->postMessage();
25198    }
25199    /**
25200     * @api {post} /payment/processRedirection/:form_type processRedirection()
25201     * @apiName processRedirection
25202     * @apiGroup Payment
25203     * @apiDescription Redirect to the correct page after payment
25204     * 
25205     * @apiParam {String} form_type Form type. Null if not set.
25206     * 
25207     * @apiSuccess {View} Redirect to the correct page after payment
25208     * 
25209     * @apiError {View} Redirect to the home page
25210     * 
25211     * @apiSuccessExample Success Response:
25212     * Redirects to {{ENV}}/payment/payment_credit_charge_complete if form_type is 'payment_credit_force_charge'
25213     * 
25214     * @apiSuccessExample Success Response:
25215     * Redirects to {{ENV}}/payment/payment_credit_retry_complete if form_type is 'payment_credit_retry'
25216     * 
25217     * @apiErrorExample Success Response:
25218     * Redirects to {{ENV}}/ if form_type is not set
25219     * 
25220     * @apiSampleRequest off
25221     */
25222    public function processRedirection($form_type = null) {
25223        if ($form_type == Configure::read('payment_credit_force_charge')) {
25224            return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_charge_complete'));
25225
25226        } else if ($form_type == Configure::read('payment_credit_retry')) {
25227            return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_retry_complete'));
25228
25229        } else {
25230            return $this->redirect(myTools::getUrl() . '/');
25231        }
25232    }
25233
25234    /**
25235     * Aftee: prepare payment form data
25236     * Create new payment transaction
25237     * get cpayment data and checksum
25238     */
25239    public function getAfteeHostedPage() {
25240        $this->layout = '';
25241
25242        if ($this->request->is('post')) {
25243            $postData = $this->request->data;
25244
25245            // throw exception if there is/are missing parameter(s)
25246            if (
25247                !isset($postData['logFileName']) ||
25248                !isset($postData['apiToken']) ||
25249                !isset($postData['formType']) ||
25250                !isset($postData['successUrl']) ||
25251                !isset($postData['paymentMethodType']) ||
25252                !isset($postData['memKeyError']) ||
25253                !isset($postData['referrer']) ||
25254                (
25255                    empty(trim($postData['apiToken'])) &&
25256                    $postData['apiToken'] !== 0 &&
25257                    $postData['apiToken'] !== '0'
25258                )
25259            ) {
25260                $this->log(__METHOD__ . ' Missing parameters. post data --> ' . json_encode($postData), $logFileName);
25261                throw new BadRequestException("Missing parameter(s).");
25262            }
25263
25264            // set variables
25265            $apiToken = $postData['apiToken'];
25266            $formType = $postData['formType'];
25267            $successUrl = urldecode($postData['successUrl']);
25268            $paymentMethodType = $postData['paymentMethodType'];
25269            $nominalAmountArr = Configure::read('aftee.nominal_amount');
25270            $memKeyError = $postData['memKeyError'];
25271            $referrer = $postData['referrer'];
25272            $status = 0; // default pending
25273
25274            $userParams = array(
25275                'fields' => array(
25276                    'User.id',
25277                    'User.email',
25278                    'User.nickname',
25279                    'User.card_token',
25280                    'User.charge_flg',
25281                    'User.fail_flg',
25282                    'User.currency_code',
25283                    'User.payment_plan_id',
25284                    'User.price_id',
25285                    'User.double_check_flg',
25286                    'User.status',
25287                    'User.complimentary_code',
25288                    'User.card_company',
25289                    'User.phone_number',
25290                    'PaymentPlanPrice.amount'
25291            ),
25292                'apiToken' => $apiToken
25293            );
25294
25295            // throw exception if api token not exist
25296            if (!$userData = $this->User->getWPMobappUserData($userParams)) {
25297                $this->log(__METHOD__ . ' User api token does not exist. User params --> ' . json_encode($userParams), $logFileName);
25298                throw new InternalErrorException("User api token does not exist.");
25299            }
25300
25301            $userCurrencyCode = $userData['User']['currency_code'];
25302
25303            // set variables
25304            $paymentPlanPriceAmount = $userData['PaymentPlanPrice']['amount'];
25305            $userData = $userData['User'];
25306            $currencyCode = $userCurrencyCode;
25307            $paymentPlanId = $userData['payment_plan_id'];
25308            $priceId = $userData['price_id'];
25309            $userId = $userData['id'];
25310            $afteePaymentAmount = $nominalAmountArr[$currencyCode];
25311            $ncPaymentAmount = 0;
25312            $preToken = $userData['card_token'];
25313            $discounted_amount = isset($userData['discounted_amount']) ?? 0;
25314
25315
25316            // get payment method (debit or credit)
25317            $paymentMethod = 'aftee';
25318
25319            switch ($formType) {
25320                case Configure::read('payment_credit_authentication'):
25321                    $tokenReason = 'Payment Credit Registration';
25322                    if (!isset($priceId)) {
25323                        // get payment data
25324                        $paymentData = $this->PaymentPlanPrice->getPaymentData(array(
25325                            'currencyCode' => $currencyCode,
25326                            'paymentPlanId' => Configure::read('payment_plans.free_trial'),
25327                            'logFileName' => $logFileName
25328                        ));
25329
25330                        // throw error exception if does not exist
25331                        if (!$paymentData) {
25332                            throw new InternalErrorException("Payment plan does not exist.");
25333                        }
25334
25335                        $priceId = $paymentData['priceId'];
25336                    }
25337                    $paymentPlanId = Configure::read('payment_plans.free_trial');
25338                    break;
25339                case Configure::read('payment_credit_change'):
25340                    if (!isset($priceId) || !isset($paymentPlanId)) {
25341                        throw new InternalErrorException("Price id or payment plan id is/are empty.");
25342                    }
25343                    $tokenReason = 'Payment Credit Change';
25344                    break;
25345                case Configure::read('payment_credit_retry'):
25346                    // get payment data
25347                    if (!$paymentData = $this->getRetryPaymentData($userData, $logFileName)) {
25348                        throw new InternalErrorException("Payment plan does not exist.");
25349                    }
25350
25351                    $afteePaymentAmount = $paymentData['amount'];
25352                    $priceId = $paymentData['priceId'];
25353                    $paymentPlanId = $paymentData['paymentPlanId'];
25354                    
25355                    // NJ-47740
25356                    $coupon = $this->UsersCouponV1->getCouponUseRequest(array(
25357                        'userId' => $userId,
25358                        'kbn' => Configure::read('coupon_kbn.monthly_settlement')
25359                    ));
25360                    
25361                    if (
25362                        !empty($coupon['result']) && 
25363                        !empty($coupon['grp_id']) && 
25364                        !empty($coupon['amount']) && 
25365                        empty($coupon['has_payment']) // exclude if coupon has payment
25366                    ) {
25367                        $afteePaymentAmount -= $userData['discounted_amount'] = $coupon['amount'];
25368                        $userData['monthlyDiscount'] = $coupon['amount'];
25369                        $userData['monthly_grp_id'] = $coupon['grp_id'];
25370                    }
25371                    // NJ-47740 end
25372
25373                    // add reserve payment amount
25374                    $afteePaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment($userId);
25375
25376                    // add appreciation lesson amount
25377                    $afteePaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('appreciation_data.payment_element_type'));
25378
25379                    // add live lesson amount
25380                    $afteePaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.live'));
25381
25382                    $ncPaymentAmount = $afteePaymentAmount;
25383
25384                    // change payment method type to auth if amount to be paid in is equal to 0
25385                    if ($afteePaymentAmount == 0) {
25386                        $paymentMethodType = $paymentMethod . '_auth';
25387                        $afteePaymentAmount = $nominalAmountArr[$currencyCode];
25388                    }
25389
25390                    $tokenReason = 'Payment Credit Retry';
25391                    break;
25392                case Configure::read('payment_credit_force_charge'):
25393                    // get payment data
25394                    $paymentData = $this->PaymentPlanPrice->getPaymentData(array(
25395                        'currencyCode' => $currencyCode,
25396                        'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
25397                        'logFileName' => $logFileName
25398                    ));
25399
25400                    // throw error exception if does not exist
25401                    if (!$paymentData) {
25402                        throw new InternalErrorException("Payment plan does not exist.");
25403                    }
25404
25405                    $afteePaymentAmount = $paymentData['amount'];
25406                    $priceId = $paymentData['priceId'];
25407                    $paymentPlanId = $paymentData['paymentPlanId'];
25408
25409                    // add reserve payment amount
25410                    $afteePaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment($userId);
25411
25412                    // add live lesson payment amount
25413                    $afteePaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment( $userId, false, Configure::read('appreciation_data.payment_element_type') );
25414
25415                    // add live lesson payment amount
25416                    $afteePaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.live'));                    
25417
25418                    $ncPaymentAmount = $afteePaymentAmount;
25419
25420                    // change payment method type to auth if amount is  equal to 0
25421                    if ($afteePaymentAmount == 0) {
25422                        $paymentMethodType = $paymentMethod . '_auth';
25423                        $afteePaymentAmount = $nominalAmountArr[$currencyCode];
25424                    }
25425
25426                    $tokenReason = 'Payment Credit Charge';
25427                    break;
25428            }
25429            $validatePhone = "/^[0-9]{10}+$/";
25430            $phoneNumber = '';
25431            if (preg_match($validatePhone, $userData['phone_number']) === 1 && substr($userData['phone_number'], 0, 2) == '09' && strlen($userData['phone_number']) == 10) {
25432                $phoneNumber = $userData['phone_number'];
25433            }
25434            $orderNumber = myTools::generateOrderCode($userId);
25435            $merchantCode = myTools::getAfteeMerchantCode();
25436            $afteePaymentParams = array(
25437                'shopItemId' => "AFTEE" . $formType,
25438                'itemName' => str_replace(' ', '', $tokenReason),
25439                'itemPrice' => $afteePaymentAmount,
25440                'itemCount' => 1,
25441                'customerPhoneNumber' => $phoneNumber,
25442                'customerEmail' => $userData['email'],
25443                'shopTransactionNo' => $orderNumber,
25444                'userID' => $userId
25445            );
25446
25447            if (!class_exists('AfteePaymentService')) {
25448                App::uses('AfteePaymentService','Lib');
25449            }
25450            $afteeService = new AfteePaymentService();
25451            $auth = ($formType == Configure::read('payment_credit_authentication') || $formType == Configure::read('payment_credit_change')) ? true : false;
25452            $afteeChecksum = $afteeService->generateChecksum($afteePaymentParams, $auth);
25453            $afteeChecksum['settlementData']['checksum'] = $afteeChecksum['checksum'];
25454            $afteePublicKey = $afteeService->getShopPublicKey();
25455
25456            $paymentParams = array(
25457                'currencyCode' => $currencyCode,
25458                'formType' => $formType,
25459                'logFileName' => $logFileName,
25460                'remoteAddress' => $_SERVER["REMOTE_ADDR"],
25461                'cardToken' => isset($userData['card_token']) ? $userData['card_token'] : null,
25462                'newCard' => true,
25463                'merchantCode' => $merchantCode,
25464                'afteePaymentAmount' => $afteePaymentAmount,
25465                'paymentAmount' => $ncPaymentAmount,
25466                'priceId' => $priceId,
25467                'paymentPlanId' => $paymentPlanId,
25468                'paymentType' => Configure::read('payment_types.payment_plan'),
25469                'discounted_amount' => $discounted_amount
25470            );
25471
25472            if (isset($postData['userRegister']) && $postData['userRegister']) {
25473                $paymentParams['userRegister'] = true;
25474
25475                $receiveBonus = UsersPointTable::checkIfUserReceiveBonusUponRegister($userId);
25476                if (!$receiveBonus && empty($userData['User']['complimentary_code'])) {
25477                    UsersPointTable::giveBonusCoins(['userId' => $userId, 'triggerNo' => 1]);
25478                }
25479            }
25480
25481            if ($formType != Configure::read('payment_credit_change')) {
25482                $membershipTypes = UserTable::getEngMembershipTypeData();
25483                $statusAfter = $membershipTypes[1]; // premium plan paid
25484
25485                /* -- get before status -- */
25486                if ($this->memcache->get('com_plan_user_' . $userId) && $userData && $userData['payment_plan_id'] == Configure::read('payment_plans.complimentary_plan')) {
25487                    $statusBefore = $membershipTypes[15]; // complimentary code
25488                    $paymentParams['bonusCoinFlg'] = 1;
25489                    $paymentParams['updateFirstChargeDate'] = true;
25490                } elseif ($userData['charge_flg'] == 0) {
25491                    // failed settlement
25492                    if ($userData['fail_flg'] == 1) {
25493                        $statusBefore = $membershipTypes[5];
25494                    // trial again
25495                    } elseif ($userData['fail_flg'] == 0 && $userData['double_check_flg'] == 1) {
25496                        $statusBefore = $membershipTypes[13];
25497                    // unsubscribed
25498                    } elseif ($userData['fail_flg'] == 0 && $userData['double_check_flg'] == 2) {
25499                        $statusBefore = $membershipTypes[12];
25500                    // temporary
25501                    } elseif ($userData['status'] == 0) {
25502                        $statusBefore = $membershipTypes[6];
25503                        $statusAfter = $membershipTypes[2]; // premium plan free
25504                    } else {
25505                        $statusBefore = null;
25506                    }
25507                }
25508
25509                if (isset($statusBefore)) {
25510                    $user = new UserTable($userData);
25511                    $membershipTypeIndex = $user->getMembershipTypeIndex();
25512
25513                    if ($membershipTypeIndex == 13) {
25514                        $statusBefore = $membershipTypes[13];
25515                        $paymentParams['userRegister'] = true;
25516                        $statusAfter = $membershipTypes[2];
25517                    }
25518
25519                    // get platform use
25520                    $platform = myTools::mobappDetectPlatform();
25521                    $paymentParams['platform'] = $platform == Configure::read('platform.splp') ? Configure::read('platform.pclp') : $platform;
25522                    $paymentParams['statusBefore'] = $statusBefore;
25523                    $paymentParams['statusAfter'] = $statusAfter;
25524
25525                    $user = new UserTable($userData);
25526                    $membershipTypeIndex = $user->getMembershipTypeIndex();
25527
25528                    if ($membershipTypeIndex == 13) {
25529                        $paymentParams['userRegister'] = true;
25530                    }
25531                }
25532            }
25533            
25534            // NC-7029: coupon discount
25535            // exclude native option and callan option coupon discount (will use on later monthly settlement)
25536            $coupon = $this->UsersCouponV1->getCouponUseRequest(array(
25537                'userId' => $userId,
25538                'kbn' => Configure::read('coupon_kbn.monthly_settlement')
25539            ));
25540            
25541            if (
25542                !empty($coupon['result']) && 
25543                !empty($coupon['grp_id']) && 
25544                !empty($coupon['amount']) && 
25545                empty($coupon['has_payment']) // exclude if coupon has payment
25546            ) {
25547                $paymentParams['discounted_amount'] = $coupon['amount'];
25548                $paymentParams['monthlyDiscount'] = $coupon['amount'];
25549                $paymentParams['monthly_grp_id'] = $coupon['grp_id'];
25550            }
25551
25552            $ptParams = array(
25553                'user_id' => $userId,
25554                'payment_hash' => $orderNumber,
25555                'status' => $status,
25556                'payment_params' => json_encode($paymentParams),
25557                'course_id' => Configure::read("credit.course_id")
25558            );
25559
25560            // throw exception if failed to save payment transaction
25561            if (!$pt = $this->PaymentTransaction->setAfteePaymentTransaction($ptParams)) {
25562                $this->log(__METHOD__ .' Failed to save payment transaction. update data --> ' . json_encode($ptParams), $logFileName);
25563                throw new InternalErrorException("Failed to save payment transaction.");
25564            }
25565
25566            $this->set('logFileName', $logFileName);
25567            $this->set('apiToken', $apiToken);
25568            $this->set('checkSum', $afteeChecksum['checksum']);
25569            $this->set('orderNumber', $orderNumber);
25570            $this->set('userId', $userId);
25571            $this->set('salesSettled', $auth ? 'false' : 'true');
25572            $this->set('afteePaymentParams', $afteePaymentParams);
25573            $this->set('afteePublicKey', $afteePublicKey);
25574            $this->set('transactionOptions', $auth);
25575            $this->set('nc_terminal_type', isset($postData['ncTerminalType']) ? $postData['ncTerminalType'] : 0);
25576            $this->set('formType', $formType);
25577            $this->set('memKeyError', 'card_regist_error_'.$apiToken);
25578            $this->set('referrer', $postData['referrer']);
25579            $this->set('successUrl', $postData['successUrl']);
25580            $this->set('userRegister', true);
25581            $this->set('ptID', $pt['id']);
25582            $this->set('preToken', $preToken);
25583        } else {
25584            throw new MethodNotAllowedException("Method used is not POST.");
25585        }
25586
25587        $this->render('/Elements/mobapp/aftee_get_hosted_page');
25588    }
25589
25590    /**
25591     * Aftee payment webhook
25592     * Kickback from aftee after payment success
25593     */
25594    public function getAfteePaymentResult(){
25595        $this->autoRender = $this->autoLayout = false;
25596        $data = $this->request->data;
25597
25598        $this->log('fetched aftee result --> ' . json_encode($data), 'aftee_debug');
25599        $orderCode = isset($data['shop_transaction_no']) && !empty($data['shop_transaction_no']) ? $data['shop_transaction_no'] : NULL;
25600        $dataJson = json_encode($data);
25601
25602        // get payment transaction data 
25603        $paymentTransactionData = $this->PaymentTransaction->getAfteePaymentTransaction($orderCode);
25604
25605        // return if payment transaction does not exist
25606        if (!$paymentTransactionData) {
25607            $msg = 'Payment transaction does not exist.';
25608            $this->log(__METHOD__ . ' ' . $msg . ' kickback data -->' . $dataJson, 'aftee_debug');
25609            exit;
25610        }
25611        $updateData = array(
25612            'id' => $paymentTransactionData['id'],
25613            'fields' => array(
25614                'response_text' => array('aftee_directPayment_response' => $dataJson))
25615        );
25616
25617        // update payment transaction with kickback data
25618        if (!$this->PaymentTransaction->updateAfteePaymentTransaction($updateData)) {
25619            $this->log(__METHOD__ .' Failed to update payment transaction. update data --> ' . json_encode($updateData), 'aftee_debug');
25620            exit;
25621        }
25622
25623        echo "[OK]"; exit;
25624    }
25625
25626    /**
25627     * Aftee authentication webhook
25628     * Kickback from aftee if phone number is valid
25629     */
25630    public function afteeAuthentication(){
25631        $this->autoRender = $this->autoLayout = false;
25632        $this->log('aftee authentication --> ' . json_encode($this->request->data), 'aftee_debug');
25633        exit;
25634    }
25635
25636    /**
25637     * NC-18006: aftee process payment transaction.
25638     * @param array $params
25639     * @return string 'ok' or exception
25640     */
25641    private function processAfteePayment($params) {
25642        $logFileName = isset($params['logFileName']) ? $params['logFileName'] : 'debug';
25643        $orderCode = isset($params['data']['OrderCode']) ? $params['data']['OrderCode'] : '';
25644        $paymentStatusName = isset($params['data']['PaymentStatus']) ? $params['data']['PaymentStatus'] : '';
25645        $userId = isset($params['ptData']['user_id']) ? $params['ptData']['user_id'] : null;
25646
25647        if (
25648            !isset($params['data']) || !isset($params['ptData']) || !isset($params['dataSource']) ||
25649            !isset($params['amount']) || !isset($params['userData'])
25650        ) {
25651            $msg = ' Missing parameters.';
25652            $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
25653            $this->log(__METHOD__ . ' ' . $msg . ' Parameters --> ' . json_encode($params), $logFileName);
25654        }
25655
25656        $membershipStatusIndex = UserTable::getStudentMembershipStatus($userId);
25657
25658        // set variables
25659        $data = $params['data'];
25660        $dataJson = json_encode($data);
25661        $dateNow = date("Y-m-d H:i:s");
25662        $paymentTransactionData = $params['ptData'];
25663        $cardCompany = Configure::read('card_company.aftee');
25664        $amount = $params['amount'];
25665        $paymentStatus = 1;
25666        $typeId = 1;
25667        $platform = Configure::read('platform.pclp');
25668        $receivablePayment = isset($params['receivablePayment']) ? $params['receivablePayment'] : 0;
25669        $appreciationReceivable = isset($params['appreciationReceivable']) ? $params['appreciationReceivable'] : 0;
25670        $liveLessonReceivable = isset($params['liveLessonReceivable']) ? $params['liveLessonReceivable'] : 0;
25671        $ptPaymentParams = json_decode($paymentTransactionData['payment_params'], true);
25672        $currencyCode = isset($ptPaymentParams['currencyCode']) ? $ptPaymentParams['currencyCode'] : null;
25673        $ptResponseText = array('aftee_kickback' => $data);
25674        $dataSource = $params['dataSource'];
25675        $ptPassword = $paymentTransactionData['password'];
25676        $formType = $ptPaymentParams['formType'];
25677        $cronDateRun = isset($params['cronDateRun']) ? $params['cronDateRun'] : date('Y-m-d H:i:s');
25678        $userData = $params['userData'];
25679        $transactionIdentifier = $params['transactionIdentifier'];
25680        $paymentPlanId = isset($ptPaymentParams['paymentPlanId']) ? $ptPaymentParams['paymentPlanId'] : null;
25681        $paymentType = isset($ptPaymentParams['paymentType']) ? $ptPaymentParams['paymentType'] : null;
25682        $discounted_amount = isset($ptPaymentParams['discounted_amount']) ? $ptPaymentParams['discounted_amount'] : 0;
25683        $priceId = isset($ptPaymentParams['priceId']) ? $ptPaymentParams['priceId'] : null;
25684        $familyId = isset($ptPaymentParams['familyId']) ? $ptPaymentParams['familyId'] : null;
25685        $parentId = isset($userData['User']['parent_id']) ? $userData['User']['parent_id'] : $ptPaymentParams['parentId'];
25686
25687        $userId = $familyId ? $familyId : $userId;
25688
25689
25690        $currency_before = $currencyCode;
25691        $plan_before = $paymentPlanId;
25692        $membershipStatusIndex = isset($ptPaymentParams['membershipStatusIndex']) && $ptPaymentParams['membershipStatusIndex'] ? $ptPaymentParams['membershipStatusIndex'] : $membershipStatusIndex;
25693        $uModel = $this->User;
25694
25695        if (in_array($formType, array(Configure::read('payment_credit_retry'), Configure::read('payment_credit_authentication')))) {
25696            $typeId = 2;
25697        } 
25698
25699        if (isset($amount) && $amount < 0) {
25700            $typeId = 0;
25701        }
25702
25703        $userData = $userData['User'];
25704        $pModel = $this->Payment;
25705
25706        // check if family plan
25707        if (
25708            $familyId && 
25709            $parentId && 
25710            (
25711                in_array($formType, array(Configure::read('payment_credit_coin_purchase'), Configure::read('payment_credit_textbook_purchase'))) 
25712                ||
25713                (
25714                    isset($ptPaymentParams['nativeOptionJoin']) && 
25715                    $ptPaymentParams['nativeOptionJoin'] && 
25716                    $ptPaymentParams['formType'] == Configure::read('payment_native_option_join')
25717                )
25718            )
25719        ) {
25720            // change reference id to parent id
25721            $referenceId = $parentId;
25722        } else {
25723            $referenceId = $userId;
25724        }
25725
25726        // set variables
25727        $paymentData = array(
25728            'user_id' => $userId,
25729            'type_id' => $typeId,
25730            'reference_id' => $referenceId,
25731            'payment_transaction_password' => $ptPassword,
25732            'status' => $paymentStatus,
25733            'form_type' => $formType,
25734            'ordd' => $orderCode,
25735            'amount' => $amount,
25736            'param1' => $dataJson,
25737            'card_company' => $cardCompany,
25738            'transaction_code' => $orderCode,
25739            'currency_code' => $currencyCode,
25740            'payment_id' => $paymentPlanId,
25741            'price_id' => $priceId,
25742            'payment_type' => $paymentType,
25743        );
25744
25745        // NC-7029: save discount amount
25746        if (isset($ptPaymentParams['discounted_amount']) && $ptPaymentParams['discounted_amount'] > 0) {
25747            $paymentData['discounted_amount'] = $ptPaymentParams['discounted_amount'];
25748        }
25749
25750        //- check payment receivable with zero amount
25751        if (
25752            $formType == Configure::read('payment_credit_receivable') &&
25753            $amount <= 0
25754        ) {
25755            //- skip saving
25756        } else {
25757            // create new payment
25758            $pModel->clear();
25759            $pModel->create();
25760            $pModel->validate = array();
25761            $pModel->set($paymentData);
25762
25763            // return if not save
25764            if (!$paymentSave = $pModel->save()) {
25765                $msg = 'Saving payment failed.';
25766                $this->log(__METHOD__ . ' ' . $msg . ' Payment data --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, $logFileName);
25767                $dataSource->rollback();
25768                $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
25769                throw new InternalErrorException($msg);
25770            }
25771            //update/add user`s settlement amount
25772            $this->User->updateUserPayments($paymentData);
25773            $paymentId = $paymentSave['Payment']['id'];
25774
25775            // set payment_id
25776            $paymentSaveID = $this->Payment->id;
25777        }
25778
25779        // if payment was saved, and form type belongs to textbook purchase,
25780        // update textbook_sales table, insert payment_id
25781        if ($formType == Configure::read('payment_credit_textbook_purchase')) {
25782            // set textbook sales info
25783            $textbookSales = $this->TextbookSale->find('first', array(
25784                'conditions' => array(
25785                    'TextbookSale.sales_code' => $ptPassword
25786                ),
25787                'recursive' => -1
25788            ));
25789            
25790            // if has textbook sales, update payment_id
25791            if ($textbookSales) {
25792                $this->TextbookSale->clear();
25793                if (!$this->TextbookSale->read(null, $textbookSales['TextbookSale']['id'])) {
25794                    $msg = 'Textbook sales id does not exist.';
25795                    $this->log(__METHOD__ . ' ' . $msg . json_encode($textbookSales), $logFileName);
25796                    $dataSource->rollback();
25797                    $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
25798                }
25799                $this->TextbookSale->set('payment_id', $paymentId);
25800                $this->TextbookSale->set('payment_status', 1);
25801                if (!$this->TextbookSale->save()) {
25802                    $msg = 'Failed to update textbook sales payment status to 1.';
25803                    $this->log(__METHOD__ . ' ' . $msg . json_encode($textbookSales), $logFileName);
25804                    $dataSource->rollback();
25805                    $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
25806                    throw new InternalErrorException($msg);
25807                }
25808            }
25809        }
25810
25811        // check if form type is not equals to textbook purchase or receivable
25812        if (
25813            $formType != Configure::read('payment_credit_coin_purchase') &&
25814            $formType != Configure::read('payment_credit_textbook_purchase') &&
25815            $formType != Configure::read('payment_credit_receivable') &&
25816            $formType != Configure::read('payment_credit_appreciation_receivable') &&
25817            $formType != Configure::read('payment_native_option_monthly_payment') &&
25818            $formType != Configure::read('payment_native_option_join')
25819        ) {
25820            // set user array to be save
25821            $saveUserArr = array(
25822                'modified' => $dateNow,
25823                'fail_flg' => 0,
25824                'charge_flg' => 1,
25825                'counseling_attended_flg' => 0,
25826                'card_company' => $cardCompany,
25827                'hash16' => $userId,
25828                'last_charge_date' => $dateNow,
25829                'aftee_transaction_identifier' => $transactionIdentifier,
25830                'payment_plan_id' => $paymentPlanId,
25831                'price_id' => $priceId
25832            );
25833
25834            // NJ-1562 - appreciation on
25835            if( $paymentPlanId && in_array( $paymentPlanId, Configure::read('appreciation.payment_plan_id') ) ) {
25836                $saveUserArr['allow_appreciation_flg'] = 1; // on
25837
25838                //NJ-7548 : 
25839                if (
25840                    !in_array($paymentPlanId,Configure::read('appreciation.can_coin_purchase_check')) &&
25841                    (
25842                        $formType == Configure::read('payment_credit_authentication') ||
25843                        $formType == Configure::read('payment_credit_change') || 
25844                        $formType == Configure::read('payment_credit_force_charge') || 
25845                        $formType == Configure::read('payment_credit_retry')
25846                    )
25847                ) {
25848                    //fetch the age
25849                    $userAge = UserTable::getStudentAge($userData['birthday']);
25850                    $userAge = $userAge ? (int) $userAge : null;
25851                    $showAppreciationFlg = 0;
25852
25853                    //change the show appreciation flg if no birthday set or 18 and above            
25854                    if (!$userAge || $userAge >= 18) {
25855                        $saveUserArr['show_appreciation_flg'] = 1; // on
25856                    }
25857                }
25858
25859            }
25860
25861            // check payment if credit authentication
25862            if (in_array($formType, array(Configure::read('payment_credit_authentication'), Configure::read('payment_credit_family_free'))) 
25863                || isset($ptPaymentParams['updateFirstChargeDate'])
25864            ) {
25865                $saveUserArr['first_charge_date'] = $dateNow;
25866                // $saveUserArr['platform'] = $platform;
25867            }
25868
25869            // if bonus coin flg is set
25870            if (isset($ptPaymentParams['bonusCoinFlg'])) {
25871                $saveUserArr['bonus_coin_flg'] = $ptPaymentParams['bonusCoinFlg'];
25872            }
25873
25874            // get time today plus 1 hour
25875            $nextChargeTime = (time() + 3600) - strtotime('TODAY');
25876
25877            // check if subscription payment
25878            if (
25879                $formType == Configure::read('payment_credit_force_charge') ||
25880                $formType == Configure::read('payment_credit_retry') ||
25881                $formType == Configure::read('payment_credit_monthly_payment') ||
25882                $formType == Configure::read('payment_credit_family_monthly_payment') ||
25883                $formType == Configure::read('payment_credit_family_free')
25884            ) {
25885
25886                if ($formType == Configure::read('payment_credit_monthly_payment')) {
25887                    $nextChargeTime = strtotime($userData['next_charge_date']) - strtotime('TODAY');
25888                }
25889
25890                // set minutes and seconds to 00:00 always
25891                $nextChargeDate = date('Y-m-d H:00:00', strtotime('+' . $nextChargeTime . ' second ' . $this->User->getNextChargeDate()));
25892                $saveUserArr['next_charge_date'] = $nextChargeDate;
25893                $saveUserArr['double_check_flg'] = 1;
25894                $saveUserArr['expired_card_flg'] = 0;
25895
25896                $this->loadModel("ContinuationCampaign");
25897
25898                // give points to user join the campaign who retry payment
25899                if ($formType == Configure::read('payment_credit_retry')) {
25900                    $this->ContinuationCampaign->givePointsRetrySuccess(array(
25901                        'user_ids' => array($userId)
25902                    ));
25903                }
25904
25905                // give points if user join campaign and success payment
25906                if ($formType == Configure::read('payment_credit_monthly_payment')) {
25907                    $this->ContinuationCampaign->givePoints(array(
25908                        'user_id' => $userId
25909                    ));
25910                }
25911
25912                if ($formType == Configure::read('payment_credit_family_free')) {                    
25913                    $nextChargeDate = date('Y-m-d H:00:00', strtotime('+' . $nextChargeTime . ' second ' . $this->User->getFirstNextChargeDate()));
25914                    $saveUserArr['next_charge_date'] = $nextChargeDate;
25915                }
25916
25917                if ($formType == Configure::read('payment_credit_family_monthly_payment')) {
25918                    $nextChargeDate = date('Y-m-d H:00:00', strtotime('+' . (time() - strtotime('TODAY')) . ' second ' . $this->User->getNextChargeDate()));
25919                    $saveUserArr['next_charge_date'] = $nextChargeDate;
25920                }
25921
25922
25923                # give coins if temporary/new user is changed/added to family plan
25924                if ($formType == Configure::read('payment_credit_family_free') && $userData['status'] == 0) {
25925                    // NJ-4746: defult bonus point
25926                    $defaultBC = ClassRegistry::init("DefaultCoinRegistration")->defaultCoins();
25927                    $bonusPoints = (($defaultBC > 0) ? $defaultBC : Configure::read("credit.bonus_coin_authentication"));
25928
25929                    // campaign master trigger 1
25930                    $campaignMaster = ClassRegistry::init('CampaignMaster')->bonusTrigger(['userId' => $userData['id'], 'triggerNo' => 1]);
25931                    if (!$campaignMaster['bonusCoins'] && !$campaignMaster['bonusCoupons']) {
25932                        # add to the user's existing coin
25933                        $pointParams = array(
25934                            'userId' => $userData['id'],
25935                            'point' => $bonusPoints,
25936                            'kbn' => Configure::read("point_history.bonus"),
25937                            'kbnType' => 1, // add coin
25938                            'coinType' => 2, // service coin
25939                            'coinFailMessage' => Configure::read('coin.failed.campaign')
25940                        );
25941                        if (!$this->UsersPoint->performPointTransaction($pointParams)) {
25942                            $msg = 'Failed add point to user.';
25943                            $this->log(__METHOD__ . ' Failed add point to user. ' . json_encode($pointParams) . ' -- ' . json_encode($data), $logFileName);
25944                            $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
25945                            $dataSource->rollback();
25946                            $dataSource->commit();
25947                            return ;
25948                        }
25949                    }
25950                }
25951
25952            } elseif ($formType == Configure::read('payment_credit_authentication')) {
25953                // set minutes and seconds to 00:00 always
25954                $nextChargeDate = date('Y-m-d H:00:00', strtotime('+' . $nextChargeTime . ' second ' . $this->User->getFirstNextChargeDate()));
25955                $saveUserArr['next_charge_date'] = $nextChargeDate;
25956            }
25957
25958            // if credit card change from android or apple to worldpay
25959            if (
25960                in_array($formType, array(Configure::read('payment_credit_change'), Configure::read('payment_credit_authentication'))) &&
25961                in_array($cardCompany, array(Configure::read('card_company.apple'), Configure::read('card_company.google')))
25962            ) {
25963
25964                $pointParams = array(
25965                    'userId' => $userId,
25966                    'point' => 500,
25967                    'kbn' => 6,
25968                    'kbnType' => 1, // add coin
25969                    'coinType' => 2, // service coin
25970                    'coinFailMessage' => Configure::read('coin.failed.campaign')
25971                );
25972
25973                if (!$this->UsersPoint->performPointTransaction($pointParams)) {
25974                    $msg = 'Adding user coin history failed.';
25975                    $this->log(__METHOD__ . ' ' . $msg . ' Point params --> ' . json_encode($pointParams) . ' | kickback data --> ' . $dataJson, $logFileName);
25976                    $dataSource->rollback();
25977                    $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
25978                    throw new InternalErrorException($msg);
25979                }
25980            }
25981
25982            $famRegist = false;
25983            // NC-4673: update family parent_id, memo and monthly_payment
25984            
25985            if (
25986                in_array($formType, Configure::read('family_plan_form_types'))
25987            ) {
25988                // if parent_id is empty
25989                if (empty($userData['parent_id'])) {
25990                    $saveUserArr['parent_id'] = $parentId;
25991                    $saveUserArr['memo'] = date('Y/m/d H:i:s')." Family plan[User]: family registration \n".$userData['memo'];
25992                    $famRegist = true;
25993
25994                    if (empty($userData['currency_code'])) {
25995                        $saveUserArr['currency_code'] = $currencyCode;
25996                    }
25997                }
25998            }
25999
26000            // get and set card token, card brand and card number
26001            // if not new registration, delete wp token
26002            if (
26003                $formType == Configure::read('payment_credit_change') ||
26004                ($formType == Configure::read('payment_credit_authentication') && isset($ptPaymentParams['newCard']) && $ptPaymentParams['newCard']) ||
26005                ($formType == Configure::read('payment_credit_retry') && isset($ptPaymentParams['newCard']) && $ptPaymentParams['newCard']) ||
26006                ($formType == Configure::read('payment_credit_force_charge') && isset($ptPaymentParams['newCard']) && $ptPaymentParams['newCard']) ||
26007                $formType == Configure::read('payment_credit_family_free') ||
26008                $formType == Configure::read('payment_credit_family_monthly_payment')
26009            ) {
26010                // if family plan payment use parent id
26011                if($formType == Configure::read('payment_credit_family_free') || $formType == Configure::read('payment_credit_family_monthly_payment')){
26012                    $authenticatedShopperId = $parentId;
26013                }else{
26014                    $authenticatedShopperId = $userId;
26015                }
26016            
26017                // set aftee authentication token
26018                $saveUserArr['card_token'] = $data['authentication_token'];
26019                $saveUserArr['card_brand'] = "AFTEE";
26020                $saveUserArr['card_number'] = substr($data['customer']['phone_number'], -4);
26021                $saveUserArr['aftee_transaction_identifier'] = $transactionIdentifier;
26022                $saveUserArr['card_company'] = Configure::read('card_company.aftee');
26023
26024            }
26025            // update user data
26026            $uModel->clear();
26027            $uModel->recursive = -1;
26028            $read = $uModel->read(array_keys($saveUserArr), $userId);
26029            $uModel->validate = array();
26030            $uModel->set($saveUserArr);
26031            if (!$uModel->save()) {
26032                $msg = 'Updating user failed.';
26033                $this->log(__METHOD__ . ' ' . $msg . ' User data --> ' . json_encode($saveUserArr) . ' | kickback data --> ' . $dataJson, $logFileName);
26034                $dataSource->rollback();
26035                $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
26036                throw new InternalErrorException($msg);
26037            }
26038
26039            // check if membership status was change
26040            if (isset($ptPaymentParams['statusBefore']) && isset($ptPaymentParams['statusAfter']) && isset($ptPaymentParams['platform'])) {
26041                $currentUser = $this->User->find('first', array(
26042                    'fields' => array('User.parent_id', 'User.currency_code', 'User.payment_plan_id'),
26043                    'conditions' => array('User.id' => $userId),
26044                    'recursive' => -1
26045                ));
26046                $parentId = $currentUser['User']['parent_id'];
26047                $is_cron = 0;
26048                if (php_sapi_name() == 'cli' || $ptPaymentParams['logFileName'] == 'retry_monthly_payment'){
26049                    $is_cron = 1;
26050                } 
26051                   $currency_after = $currentUser['User']['currency_code'];
26052                   $plan_after = $currentUser['User']['payment_plan_id'];
26053                $usclData = array(
26054                    'user_id' => $userId,
26055                    'platform' => $ptPaymentParams['platform'] ?? '',
26056                    'card_company_before' => $read['User']['card_company'],
26057                    'status_before' => $ptPaymentParams['statusBefore'],
26058                    'status_after' => $ptPaymentParams['statusAfter'],
26059                    'controller_name' => $this->request->params['controller'],
26060                    'action_name' => $this->request->params['action'],
26061                    'parent_id' => $parentId,
26062                    'is_cron' => $is_cron,
26063                    'currency_before' => $currency_before,
26064                    'currency_after' => $currency_after,
26065                    'payment_plan_id_before' => $plan_before,
26066                    'payment_plan_id_after' => $plan_after
26067                );
26068
26069                // save user change membership status
26070                if (!$this->UserStatusChangeLog->saveLog($usclData)) {
26071                    $msg = 'Saving user status change log failed.';
26072                    $dataSource->rollback();
26073                    $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
26074                    throw new InternalErrorException($msg);
26075                }
26076            }
26077
26078            // NC-7459 check previus user status, add coinbox challenge
26079            if (
26080                isset($userData['payment_plan_id'])
26081                && $userData['payment_plan_id'] == Configure::read('payment_plans.complimentary_plan')
26082                && isset($userData['complimentary_code'])
26083            ) {
26084
26085                // get complimentary coin award
26086                $coinAward = $this->ComplimentaryCode->find('first', array(
26087                    'fields' => array('coin_award'),
26088                    'conditions' => array(
26089                        'ComplimentaryCode.code' => $userData['complimentary_code'],
26090                        'ComplimentaryCode.template_type !=' => 0 // Free trial
26091                    )
26092                ));
26093
26094                if (
26095                    isset($coinAward['ComplimentaryCode']['coin_award'])
26096                    && $coinAward['ComplimentaryCode']['coin_award']
26097                ) { // @TODO use common @note did not use CoinBox->addCoinReward because it will not succeed for unknown reason.
26098                    $coinboxSet = array(
26099                        'status' => 1,
26100                        'user_id' => $userId,
26101                        'teacher_id' => null,
26102                        'coin_event_id' => Configure::read('coin_box_event.complimentary'),
26103                        'coin' => $coinAward['ComplimentaryCode']['coin_award'],
26104                        'lesson_id' => NULL,
26105                        'expiration_date' => date('Y-m-d 23:59:59', strtotime('+59 days'))
26106                    );
26107                    $this->CoinBox->create();
26108                    $this->CoinBox->set($coinboxSet);
26109                    if (!$this->CoinBox->save()) {
26110                        $msg = 'Saving user coin box failed.';
26111                        $dataSource->rollback();
26112                        $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
26113                        throw new InternalErrorException($msg);
26114                    }
26115                }
26116            }
26117
26118            // if parent user update children's card company
26119            if ($formType == Configure::read('payment_credit_change')) {
26120                $childList = $this->User->getChildId($userId);
26121                // check if user is parent
26122                if (!empty($childList)) {
26123                    foreach ($childList as $childId) {
26124                        $this->User->clear();
26125                        $updateCCArr = array('card_company' => $cardCompany);
26126                        if (!$this->User->read(array_keys($updateCCArr), $childId)) {
26127                            $this->log(__METHOD__ . ' child id does not exist.  --> ' . json_encode($updateCCArr) . ' | parent id --> ' . $userId . ' | aftee data --> ' . json_encode($ptPaymentParams), $logFileName);
26128                            $dataSource->rollback();
26129                            $dataSource->commit();
26130                            return ;
26131                        }
26132
26133                        $this->User->set($updateCCArr);
26134                        if (!$this->User->save()) {
26135                            $this->log(__METHOD__ . ' failed to update child card company.   --> ' . json_encode($updateCCArr) . ' | parent id --> ' . $userId . ' | aftee data --> ' . json_encode($ptPaymentParams), $logFileName);
26136                            $dataSource->rollback();
26137                            $dataSource->commit();
26138                            return ;
26139                        }
26140                    }
26141                }
26142            }
26143
26144            $memKey = 'family_reactivation_' . $parentId . '_' . $familyId;
26145            $familyReactivation = $this->memcache->get($memKey);
26146
26147            // NC-3754 : add memo for reactivation parent user.
26148            if ($formType == Configure::read('payment_credit_family_monthly_payment') && !empty($userData['parent_id']) && $familyReactivation) {
26149                $famRegist = false;
26150                // delete memcache
26151                $this->memcache->delete($memKey);
26152                $this->User->clear();
26153                if (!$userRead = $this->User->read(array('memo'), $parentId)) {
26154                    $msg = 'User id does not exist';
26155                    $this->log(__METHOD__ . ' User id does not exist. ' . json_encode($ptPaymentParams), $logFileName);
26156                    $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
26157                    $dataSource->rollback();
26158                    $dataSource->commit();
26159                    return ;
26160                }
26161
26162                $this->User->set(array('memo' => date('Y/m/d H:i:s')." Family plan[User]: family id: " . $userData['id'] . " reactivation \n" . $userRead['User']['memo']));
26163                $this->User->validate = false;
26164                if (!$this->User->save()) {
26165                    $msg = 'User id does not exist';
26166                    $this->log(__METHOD__ . ' Failed update user data. ' . json_encode($userRead) . ' -- ' . json_encode($ptPaymentParams), $logFileName);
26167                    $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
26168                    $dataSource->rollback();
26169                    $dataSource->commit();
26170                    return ;
26171                }
26172            }
26173            
26174            // Proccess Family Plan
26175            if($famRegist && !$familyReactivation) {
26176                // @param:  parent id. for memcache key.
26177                $famPlanRes = $this->FamilyPlanList->processFamPlan($parentId, $familyId, $orderCode);
26178                if ($famPlanRes != "[OK]") {
26179                    $msg = 'Failed processing family plan.';
26180                    $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
26181                    $dataSource->rollback();
26182                    $dataSource->commit();
26183                    return;
26184                }
26185            }
26186            
26187            // check if user's status is temporary
26188            if (
26189                $userData['status'] == 0 && 
26190                (
26191                    $formType == Configure::read('payment_credit_authentication') || 
26192                    $formType == Configure::read('payment_credit_family_monthly_payment') || 
26193                    $formType == Configure::read('payment_credit_family_free')
26194                )
26195            ) {
26196                // update user's status after step 4
26197                $uModel->clear();
26198                $uModel->read(array('status'), $userId);
26199                $uModel->validate = array();
26200                $uModel->set('status', 1);
26201                if (!$uModel->save()) {
26202                    $msg = 'Failed to update user status into 1.';
26203                    $this->log(__METHOD__ . ' ' . $msg . ' User id --> ' . json_encode($userId) . ' | kickback data --> ' . $dataJson, $logFileName);
26204                    $dataSource->rollback();
26205                    $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
26206                    throw new InternalErrorException($msg);
26207                }
26208            }
26209            
26210            // NC-7779 : check if user has chivox monthly test taken for the current month, and monthly_speaking_attended_flg ON,
26211            // turn Off the flag if users has not yet taken the exam for the current month.
26212            if (
26213                isset($userData['monthly_speaking_attended_flg']) && isset($userData['monthly_speaking_business_attended_flg'])
26214                && ($userData['monthly_speaking_attended_flg'] == 1 || $userData['monthly_speaking_business_attended_flg'] == 1)
26215            ) {
26216                // check chivox monthly
26217                $paymentPlanIdsForChivoxMonthly = Configure::read('chivox.monthly.user_payment_plan_cantake_exam');
26218                if (in_array($paymentPlanId, $paymentPlanIdsForChivoxMonthly)) {
26219
26220                    // load model
26221                    $this->loadModel("UsersChivoxMonthlyTest");
26222                    $userTestMonthFlagParams['user_id'] = $userId;
26223                    $userTestMonthFlag = $this->UsersChivoxMonthlyTest->checkUserCurrentMonthExam($userTestMonthFlagParams);
26224
26225                    $monthly_speaking_attended_flg = Configure::read('chivox.test_data_test_type.daily'); // test_type daily speaking 0
26226                    $monthly_speaking_business_attended_flg = Configure::read('chivox.test_data_test_type.business'); // test_type business 1
26227                    $fieldsToUpdate = array();
26228
26229                    // if user hat not yet taken the exam for current month
26230                    if (!in_array($monthly_speaking_attended_flg, $userTestMonthFlag)) {
26231                        $fieldsToUpdate['monthly_speaking_attended_flg'] = 0;
26232                    }
26233                    if (!in_array($monthly_speaking_business_attended_flg, $userTestMonthFlag)) {
26234                        $fieldsToUpdate['monthly_speaking_business_attended_flg'] = 0;
26235                    }
26236
26237                    if ($fieldsToUpdate) {
26238                        $uModel->clear();
26239                        $uModel->recursive = -1;
26240                        $uModel->read(array_keys($fieldsToUpdate), $userId);
26241                        $uModel->validate = array();
26242                        $uModel->set($fieldsToUpdate);
26243                        if (!$uModel->save()) {
26244                            $msg = 'Failed to update user monthly_speaking_attended_flg into 0.';
26245                            $this->log(__METHOD__ . ' ' . $msg . ' User id --> ' . json_encode($userId) . ' | kickback data --> ' . $dataJson, $logFileName);
26246                            $dataSource->rollback();
26247                            $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
26248                            throw new InternalErrorException($msg);
26249                        }
26250                    }
26251                }
26252            }
26253        }
26254
26255        // if purchase coin
26256        if ($formType == Configure::read('payment_credit_coin_purchase') && isset($ptPaymentParams['coinPurchasePoints'])) {
26257            // change user id to child id
26258            if($familyId){
26259                $pointParamsUserId = $familyId;
26260            }else{
26261                $pointParamsUserId = $userId;
26262            }
26263
26264            $pointParams = array(
26265                'userId' => $pointParamsUserId,
26266                'point' => $ptPaymentParams['coinPurchasePoints'],
26267                'kbn' => 7,
26268                'kbnType' => 1, // add coins
26269                'coinType' => 1, // purchase coins
26270                'device' => isset($ptPaymentParams['device']) ? $ptPaymentParams['device'] : null
26271            );
26272
26273            if (!$this->UsersPoint->performPointTransaction($pointParams)) {
26274                $msg = 'Adding user coin history failed.';
26275                $this->log(__METHOD__ . ' ' . $msg . json_encode($pointParams) . ' -- ' . $dataJson, $logFileName);
26276                $dataSource->rollback();
26277                $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
26278                throw new InternalErrorException($msg);
26279            }
26280        }
26281
26282        // [Aftee] check if receivable payment sent was either
26283        // receivable payment, monthly payment, force settlement, or retry payment
26284        // if yes, set receivable payments to "received"
26285        if (
26286            in_array($formType, array(
26287                Configure::read('payment_credit_appreciation_receivable'),
26288                Configure::read('payment_credit_receivable'),
26289                Configure::read('payment_credit_monthly_payment'),
26290                Configure::read('payment_credit_force_charge'),
26291                Configure::read('payment_credit_retry'),
26292                Configure::read('payment_credit_family_monthly_payment')
26293            ))
26294        ) {
26295            // create new payment receivable
26296            if ($formType != Configure::read('payment_credit_receivable') && $receivablePayment) {
26297                // set payment id
26298                $data["payment_id"] = $paymentId;
26299
26300                // set variables
26301                $paymentData = array(
26302                    'user_id' => $userId,
26303                    'type_id' => $typeId,
26304                    'reference_id' => $userId,
26305                    'status' => $paymentStatus,
26306                    'form_type' => Configure::read('payment_credit_receivable'),
26307                    'ordd' => $orderCode,
26308                    'amount' => $receivablePayment,
26309                    'param1' => $dataJson,
26310                    'card_company' => $cardCompany,
26311                    'transaction_code' => $orderCode,
26312                    'currency_code' => $currencyCode,
26313                    'payment_id' => $paymentPlanId,
26314                    'price_id' => $priceId,
26315                    'payment_type' => $paymentType,
26316                    'discounted_amount' => 0
26317                );
26318
26319                // create new payment
26320                $pModel->clear();
26321                $pModel->create();
26322                $pModel->validate = array();
26323                $pModel->set($paymentData);
26324
26325                if (!$pModel->save()) {
26326                    $msg = 'Saving payment receivable failed.';
26327                    $this->log(__METHOD__ . ' ' . $msg . ' Params --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, $logFileName);
26328                    $dataSource->rollback();
26329                    $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
26330                    throw new InternalErrorException($msg);
26331                }
26332                //update/add user`s settlement amount
26333                $this->User->updateUserPayments($paymentData);
26334                // set payment_id
26335                $paymentId = $pModel->id;
26336
26337            }
26338
26339            // set payment receivable statuses to 2 - received
26340            $this->PaymentReceivable->updateReceivableReservationPayment(
26341                $userId, 
26342                array(
26343                    'status' => 2,
26344                    'payment_id' => $paymentId,
26345                    'payment_collection_date' => $dateNow,
26346                    'card_company' => $cardCompany,
26347                    'payment_plan_id' => $paymentPlanId,
26348                    'membership_type_index' => $membershipStatusIndex
26349                ),
26350                array(
26351                    'PaymentReceivable.user_id' => $userId,
26352                    'PaymentReceivable.status' => 0,
26353                    'PaymentReceivable.payment_element_type' => 1,
26354                    'PaymentReceivable.created <=' => $cronDateRun
26355                )
26356            );
26357
26358            // create new appreciation lesson payment receivable
26359            if ($formType != Configure::read('payment_credit_appreciation_receivable') && $appreciationReceivable > 0) {
26360                // set payment id
26361                $data["payment_id"] = $paymentId;
26362                //reset payment data
26363                $paymentData = array();
26364
26365                // set variables
26366                $paymentData = array(
26367                    'user_id' => $userId,
26368                    'type_id' => $typeId,
26369                    'reference_id' => $userId,
26370                    'status' => $paymentStatus,
26371                    'form_type' => Configure::read('appreciation_data.payment_form_type'),
26372                    'ordd' => $orderCode,
26373                    'amount' => $appreciationReceivable,
26374                    'param1' => $dataJson,
26375                    'card_company' => $cardCompany,
26376                    'transaction_code' => $orderCode,
26377                    'currency_code' => $currencyCode,
26378                    'payment_id' => $paymentPlanId,
26379                    'price_id' => $priceId,
26380                    'payment_type' => $paymentType,
26381                    'discounted_amount' => 0
26382                );
26383
26384                // create new payment
26385                $pModel->clear();
26386                $pModel->create();
26387                $pModel->validate = array();
26388                $pModel->set($paymentData);
26389
26390                if (!$pModel->save()) {
26391                    $msg = 'Saving appreciation payment receivable failed.';
26392                    $this->log(__METHOD__ . ' ' . $msg . ' Params --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, $logFileName);
26393                    $dataSource->rollback();
26394                    $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
26395                    throw new InternalErrorException($msg);
26396                }
26397                //update/add user`s settlement amount
26398                $this->User->updateUserPayments($paymentData);
26399                // set payment_id
26400                $paymentId = $pModel->id;
26401    
26402            }
26403
26404            // set payment receivable statuses to 2 - received
26405            $this->PaymentReceivable->updateReceivableReservationPayment(
26406                $userId, 
26407                array(
26408                    'status' => 2,
26409                    'payment_id' => $paymentId,
26410                    'payment_collection_date' => $dateNow,
26411                    'card_company' => $cardCompany,
26412                    'payment_plan_id' => $paymentPlanId,
26413                    'membership_type_index' => $membershipStatusIndex
26414                ),
26415                array(
26416                    'PaymentReceivable.user_id' => $userId,
26417                    'PaymentReceivable.status' => 0,
26418                    'PaymentReceivable.payment_element_type' => Configure::read('appreciation_data.payment_element_type'),
26419                    'PaymentReceivable.created <=' => $cronDateRun
26420                )
26421            );
26422
26423            // create new live lesson payment receivable
26424            if ($formType != Configure::read('payment_live_lesson_receivable') && $liveLessonReceivable) {
26425                // set payment id
26426                $data["payment_id"] = $paymentId;
26427
26428                // set variables
26429                $paymentData = array(
26430                    'user_id' => $userId,
26431                    'type_id' => $typeId,
26432                    'reference_id' => $userId,
26433                    'status' => $paymentStatus,
26434                    'form_type' => Configure::read('payment_live_lesson_receivable'),
26435                    'ordd' => $orderCode,
26436                    'amount' => $liveLessonReceivable,
26437                    'param1' => $dataJson,
26438                    'card_company' => $cardCompany,
26439                    'transaction_code' => $orderCode,
26440                    'currency_code' => $currencyCode,
26441                    'payment_id' => $paymentPlanId,
26442                    'price_id' => $priceId,
26443                    'payment_type' => $paymentType,
26444                    'discounted_amount' => 0
26445                );
26446
26447                // create new payment
26448                $pModel->clear();
26449                $pModel->create();
26450                $pModel->validate = array();
26451                $pModel->set($paymentData);
26452
26453                if (!$pModel->save()) {
26454                    $msg = 'Saving payment receivable failed.';
26455                    $this->log(__METHOD__ . ' ' . $msg . ' Params --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, $logFileName);
26456                    $dataSource->rollback();
26457                    $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
26458                    throw new InternalErrorException($msg);
26459                }
26460                //update/add user`s settlement amount
26461                $this->User->updateUserPayments($paymentData);
26462                // set payment_id
26463                $paymentId = $pModel->id;
26464            }
26465
26466            // set payment receivable statuses to 2 - received
26467            $this->PaymentReceivable->updateReceivableReservationPayment(
26468                $userId, 
26469                array(
26470                    'status' => 2,
26471                    'payment_id' => $paymentId,
26472                    'payment_collection_date' => $dateNow,
26473                    'card_company' => $cardCompany,
26474                    'payment_plan_id' => $paymentPlanId,
26475                    'membership_type_index' => $membershipStatusIndex
26476                ),
26477                array(
26478                    'PaymentReceivable.user_id' => $userId,
26479                    'PaymentReceivable.status' => 0,
26480                    'PaymentReceivable.payment_element_type' => Configure::read('payment_element_type.live'),
26481                    'PaymentReceivable.created <=' => $cronDateRun
26482                )
26483            );    
26484        }
26485
26486
26487        // NC-7029: CHECK REFERRAL USER
26488        if (
26489            in_array($formType, array(
26490                Configure::read('payment_credit_monthly_payment'),
26491                Configure::read('payment_credit_force_charge'),
26492                Configure::read('payment_credit_retry'),
26493                Configure::read('payment_credit_authentication')
26494            ))
26495        ) {
26496            $ruData = array(
26497                'referee_id' => $userId,
26498                'payment_plan_id' => $paymentPlanId,
26499                'currency_code' => isset($userData['currency_code']) ? $userData['currency_code'] : Configure::read('pc_allowed_currencies.zh-tw'),
26500                'logFileName' => $logFileName,
26501                'form_type' => $formType
26502            );
26503
26504            $couponReferredData = $this->UsersReferral->checkReferredUser($ruData);
26505            if (isset($couponReferredData['error']) && $couponReferredData['error']) {
26506                $msg = 'Failed to update users referral event flg.';
26507                $this->log(__METHOD__ . ' ' . $msg . ' Params --> ' . json_encode($ruData) . ' | kickback data --> ' . $dataJson, $logFileName);
26508                $dataSource->rollback();
26509                $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
26510                throw new InternalErrorException($msg);
26511            }
26512
26513            $couponMailId = Configure::read('site_in_mail.coupon_mail_template_id');
26514
26515            // send coupon mail to referee
26516            if (isset($couponReferredData['sendMailToReferee']) && $couponReferredData['sendMailToReferee']) {
26517                $refereeData = array(
26518                    'id' => $userData['id'],
26519                    'email' => $userData['email'],
26520                    'native_language2' => $userData['native_language2'],
26521                    'hash' => $userData['hash'],
26522                    'refereeName' => $userData['nickname'],
26523                    'referrerName' => $couponReferredData['referrerName'],
26524                    'couponAmount' => $couponReferredData['refereeSaveAmount'],
26525                    'couponUpdatedTotal' => $couponReferredData['refereeUpdatedTotal']
26526                );
26527
26528                // send mail to referee
26529                myMailer::sendTemplateMail($couponMailId, $userData['email'], $refereeData, array(), 'User');
26530            }
26531
26532            // send coupon mail to referer
26533            if (isset($couponReferredData['sendMailToReferer']) && $couponReferredData['sendMailToReferer']) {
26534                $referrerData = array(
26535                    'id' => $couponReferredData['referrerId'],
26536                    'email' => $couponReferredData['referrerEmail'],
26537                    'native_language2' => $couponReferredData['nativeLanguage2'],
26538                    'hash' => $couponReferredData['referrerHash'],
26539                    'refereeName' => $userData['nickname'],
26540                    'referrerName' => $couponReferredData['referrerName'],
26541                    'couponAmount' => $couponReferredData['refererSaveAmount'],
26542                    'couponUpdatedTotal' => $couponReferredData['refererUpdatedTotal']
26543                );
26544
26545                // send mail to referrer
26546                myMailer::sendTemplateMail($couponMailId, $couponReferredData['referrerEmail'], $referrerData, array(), 'User');
26547            }
26548
26549            // NJ-47740
26550            if (!empty($ptPaymentParams['monthlyDiscount']) && !empty($ptPaymentParams['monthly_grp_id'])) {
26551                // confirm coupon use request for discount
26552                $requestCouponConfirmData = array(
26553                    'grpId' => $ptPaymentParams['coupon_request_id'],
26554                    'paymentId' => $paymentSaveID
26555                );
26556                $result_confirm = $this->UsersCouponV1->performCouponConfirm($requestCouponConfirmData);
26557                
26558                if (!$result_confirm) {
26559                    $this->log(__METHOD__ . ' Failed to confirm coupon use request. ' . json_encode($requestCouponConfirmData) . ' -- ' . $dataJson, $logFileName);
26560                    $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
26561                }
26562            }
26563            
26564            //update/add user`s settlement amount
26565            $this->User->updateUserPayments($paymentData);
26566        } 
26567
26568        // if has native speaker payment
26569        if (
26570            isset($ptPaymentParams['nativeOptionPayment']) && $ptPaymentParams['nativeOptionPayment'] > 0
26571            && in_array($ptPaymentParams['formType'], array(Configure::read('payment_credit_monthly_payment'), Configure::read('payment_credit_family_monthly_payment')))
26572        ) {
26573            $nspFormType = Configure::read('payment_native_option_monthly_payment');
26574
26575            // check if family plan
26576            if ($familyId && $parentId) {
26577                // change reference id to parent id
26578                $referenceId = $parentId;
26579            } else {
26580                $referenceId = $userId;
26581            }
26582
26583            $paymentData = array(
26584                'user_id' => $userId,
26585                'type_id' => $typeId,
26586                'reference_id' => $referenceId,
26587                'payment_transaction_password' => $ptPassword,
26588                'status' => $paymentStatus,
26589                'form_type' => $nspFormType,
26590                'ordd' => $orderCode,
26591                'amount' => $ptPaymentParams['nativeOptionPayment'],
26592                'param1' => $dataJson,
26593                'card_company' => $cardCompany,
26594                'transaction_code' => $orderCode,
26595                'currency_code' => $currencyCode,
26596                'payment_id' => $paymentPlanId,
26597                'price_id' => $priceId,
26598                'payment_type' => Configure::read('payment_types.native_option'),
26599                'discounted_amount' => $discounted_amount
26600            );
26601
26602            // create new payment
26603            $pModel->clear();
26604            $pModel->create();
26605            $pModel->validate = array();
26606            $pModel->set($paymentData);
26607
26608            if (!$pModel->save()) {
26609                $msg = 'Saving payment receivable failed.';
26610                $this->log(__METHOD__ . ' ' . $msg . ' Params --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, $logFileName);
26611                $dataSource->rollback();
26612                $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
26613                throw new InternalErrorException($msg);
26614            }
26615
26616            //update/add user`s settlement amount
26617            $this->User->updateUserPayments($paymentData);
26618        }
26619        
26620        // activate the user native option (new, resume, and monthly payment)
26621        if (isset($ptPaymentParams['nativeOptionPayment']) && $ptPaymentParams['nativeOptionPayment'] > 0) { 
26622            $this->log(__METHOD__ . ' NJ-2388 debug Payment Transaction Data: ' . json_encode($paymentTransactionData), 'native_option_debug');
26623            $this->User->userNativeOptionProcess(array('user_id' => $userId, 'type' => 'on'));
26624
26625            //NJ-2814 add logs
26626            if (isset($ptPaymentParams['nativeOptionJoin']) && $ptPaymentParams['nativeOptionJoin']) {
26627                $nativeStatus = 1; // subscribed
26628                $statusBefore = '';
26629            } else {
26630                $nativeStatus = 2; // Monthly Continue
26631                $statusBefore = 1;
26632            }
26633
26634            $optionLogParams = array(
26635                'user_id' => $userId,
26636                'platform' => $ptPaymentParams['platform'],
26637                'status' => $nativeStatus,
26638                'controller_name' => $this->request->params['controller'],
26639                'action_name' => $this->request->params['action'],
26640                'user_type' => 0, // user
26641                'option_before' => $statusBefore,
26642                'option_after' => 1,
26643                'option_before_name' => '',
26644                'option_after_name' => 'Native Unlimited Option',
26645                'payment_plan_id' => $paymentPlanId
26646            );
26647
26648            ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
26649
26650            // - save registration status step
26651            $stepKey = Configure::read('registration_steps.user_info_entry');
26652            $this->saveStep($userId, $stepKey);
26653        }
26654
26655        // update payment transaction payment id, status and response text
26656        $ptUpdate = $this->updatePaymentTransaction(array(
26657            'id' => $paymentTransactionData['id'],
26658            'fields' => array(
26659                'status' => 1, // done
26660                'payment_id' => $paymentId,
26661                'response_text' => $ptResponseText
26662            ),
26663            'logFileName' => $logFileName
26664        ));
26665
26666        if (!$ptUpdate) {
26667            $msg = 'Updating payment transaction failed.';
26668            $dataSource->rollback();
26669            $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
26670            throw new InternalErrorException($msg);
26671        }
26672
26673        // final save
26674        $dataSource->commit();
26675
26676        // add registration bonus if user registration
26677        if (isset($ptPaymentParams['userRegister']) && $ptPaymentParams['userRegister']) {
26678            UsersPointHistoryTable::checkDailyBonus($userId);
26679            $params = array(
26680                "type" => 1, // kickback
26681                "userID" => $userId
26682            );
26683
26684            // add referral coin NC-9359
26685            $this->User->addReferralBonus($params);
26686
26687            $receiveBonus = UsersPointTable::checkIfUserReceiveBonusUponRegister($userId);
26688            if (!$receiveBonus && empty($userData['User']['complimentary_code'])) {
26689                UsersPointTable::giveBonusCoins(['userId' => $userId, 'triggerNo' => 1]);
26690            }
26691        }
26692
26693        // campaign master trigger 2
26694        if (
26695            $formType == Configure::read('payment_credit_monthly_payment') && 
26696            $userData['payment_plan_id'] == Configure::read('payment_plans.free_trial')
26697        ) {
26698            UsersPointTable::giveBonusCoins(['userId' => $userId, 'triggerNo' => 2]);
26699        }
26700
26701        // Teacher Perks : Student re-enroll
26702        if ( $formType == Configure::read('payment_credit_force_charge')) {
26703            ClassRegistry::init('TeacherPerksAccount')->reEnroll(['user_id' => $userId]);
26704        }
26705
26706        // campaign master trigger 5
26707        $this->retrial_confiscate_coins([
26708            'formType' => $formType,
26709            'paymentPlanId' => $paymentPlanId,
26710            'userId' => $userId
26711        ]);
26712
26713        // send event to adjust
26714        $adjustParams = array(
26715            'formType' => $formType,
26716            'statusBefore' => isset($ptPaymentParams['statusBefore']) ? $ptPaymentParams['statusBefore'] : null,
26717            'userId' => $userId
26718        );
26719        UserTable::sendEventToAdjust($adjustParams);
26720    }
26721
26722    /** 
26723     * Aftee slack error reporting
26724    */
26725    private function slackAfteePErrorPostMsg($paymentHash = '', $userId = '', $errMsg = '', $paymentStatus = '') {
26726        $mySlack = new mySlack();
26727        $mySlack->channel = myTools::checkChannel("#nc-aftee-fail", "#fdc-test-channel");
26728        $mySlack->username = "AFTEE ERROR REPORT";
26729        $mySlack->link_names = true;
26730        $mySlack->text = "```";
26731        $mySlack->text .= "payment_hash: {$paymentHash}\n";
26732        $mySlack->text .= "payment_status: {$paymentStatus}\n";
26733        $mySlack->text .= "user_id: {$userId}\n";
26734        $mySlack->text .= "error: {$errMsg}\n";
26735        $mySlack->text .= "```";
26736        $mySlack->sendSlack();
26737    }
26738
26739    /**
26740     * Aftee Modal Authentication
26741     * Save payment data and update membership type
26742     * handle payment transaction success from aftee modal
26743     */
26744    public function handleAfteeAuthenticationSuccess(){
26745        $this->autoRender = $this->autoLayout = false;
26746        $logFileName = isset($this->request->data['logFileName']) ? $this->request->data['logFileName'] : 'debug';
26747        $response = array();
26748
26749        // get post data
26750        if ($this->request->is('post')) {
26751            $data = $this->request->data;
26752        }
26753
26754        // if empty data
26755        if ( !isset($data) || !isset($data['success']) || 
26756            !isset($data['success']['authorization_result']) || 
26757            !isset($data['logFileName']) ||
26758            !isset($data['apiToken']) ||
26759            !isset($data['formType']) ||
26760            !isset($data['successUrl']) ||
26761            !isset($data['memKeyError']) ||
26762            !isset($data['referrer']) ||
26763            (
26764                empty(trim($data['apiToken'])) &&
26765                $data['apiToken'] !== 0 &&
26766                $data['apiToken'] !== '0'
26767            )
26768        ) {
26769            $this->log(__METHOD__ . ' Missing parameters. post data --> ' . json_encode($data), $logFileName);
26770            throw new BadRequestException("Missing parameter(s).");
26771        }
26772
26773        // merge post data
26774        $successData = $data['success'];
26775        $successData['authentication_token'] = $data['authentication_token'];
26776        $data = $successData;    
26777
26778        // set variables
26779        $orderCode = isset($data['shop_transaction_no']) && !empty($data['shop_transaction_no']) ? $data['shop_transaction_no'] : NULL;
26780        $data['OrderCode'] = $orderCode;
26781        $paymentStatusName = isset($data['authorization_result']) && !empty($data['authorization_result']) ? $data['authorization_result'] : '';
26782        $afteeTransactionIdentifier = isset($data['id']) && !empty($data['id']) ? $data['id'] : NULL;
26783        if (isset($data['related_transaction']) && !empty($data['related_transaction'])) {
26784            $afteeTransactionIdentifier = $data['related_transaction'];
26785        }
26786        $dataJson = json_encode($data);
26787
26788        // get payment transaction data 
26789        $paymentTransactionData = $this->PaymentTransaction->getAfteePaymentTransaction($orderCode);
26790
26791        // return if payment transaction does not exist
26792        if (!$paymentTransactionData) {
26793            $msg = 'Payment transaction does not exist.';
26794            $this->log(__METHOD__ . ' ' . $msg . ' kickback data -->' . $dataJson, 'aftee_debug');
26795            throw new InternalErrorException($msg);
26796        }
26797
26798        if (!isset($paymentTransactionData['user_id'])) {
26799            $msg = ' array key user_id does not exist.';
26800            $this->log(__METHOD__ . ' ' . $msg . ' kickback data -->' . $dataJson, 'aftee_debug');
26801            throw new InternalErrorException($msg);
26802            exit;
26803        }
26804
26805        // set variables
26806        $userId = $paymentTransactionData['user_id'];
26807        $cardCompany = Configure::read('card_company.aftee');
26808        $typeId = 1; // default
26809        $ptPaymentParams = json_decode($paymentTransactionData['payment_params'], true);
26810        $logFileName = isset($ptPaymentParams['logFileName']) ? $ptPaymentParams['logFileName'] : 'debug';
26811        $currencyCode = isset($ptPaymentParams['currencyCode']) ? $ptPaymentParams['currencyCode'] : null;
26812        $formType = $ptPaymentParams['formType'];
26813        $cronDateRun = isset($ptPaymentParams['cronDateRun']) ? $ptPaymentParams['cronDateRun'] : date('Y-m-d H:i:s');
26814        $familyId = isset($ptPaymentParams['familyId']) ? $ptPaymentParams['familyId'] : null;
26815        $userId = $familyId ? $familyId : $userId;
26816        $receivablePayment = $liveLessonReceivable = 0;
26817
26818        //remove user from currently paying users
26819        UserTable::removePayingUserFromMemcache($userId);
26820
26821        if (!isset($ptPaymentParams['paymentAmount'])) {
26822            $msg = 'Payment amount in payment transaction does not exist.';
26823            $this->log(__METHOD__ . ' ' . $msg . ' kickback data -->' . $dataJson . ' - ' . json_encode($ptPaymentParams), $logFileName);
26824            throw new InternalErrorException($msg);
26825            exit;
26826        }
26827
26828        $amount = $ptPaymentParams['paymentAmount'];
26829
26830        // set user model
26831        $uModel = $this->User;
26832
26833        // get user data
26834        $userData = $uModel->find('first', array(
26835            'fields' => array(
26836                'status',
26837                'nickname',
26838                'email',
26839                'hash',
26840                'memo',
26841                'parent_id',
26842                'next_charge_date',
26843                'complimentary_code',
26844                'payment_plan_id',
26845                'monthly_speaking_attended_flg',
26846                'monthly_speaking_business_attended_flg',
26847                'id',
26848                'hash16',
26849                'currency_code',
26850                'native_language2',
26851                'charge_flg',
26852                'fail_flg',
26853                'double_check_flg',
26854                'birthday',
26855                'native_option',
26856                'card_company',
26857                'card_token',
26858                'aftee_transaction_identifier'
26859            ),
26860            'conditions' => array('id' => $userId),
26861            'recursive' => -1
26862        ));
26863
26864        // return if user does not exist
26865        if (!$userData) {
26866            $msg = "User does not exist";
26867            $this->log(__METHOD__ . ' User does not exist. payment transaction data --> ' . json_encode($paymentTransactionData) . ' | kickback data --> ' . $dataJson, $logFileName);
26868            throw new InternalErrorException($msg);
26869        }
26870
26871        // NC-9168: if card auth and user's currency does not match with processed payment currency, update to correct currency
26872        if (!$userData['User']['currency_code']) {
26873            if ($formType == Configure::read('payment_credit_authentication') && $currencyCode != $userData['User']['currency_code']) {
26874                $uModel->validate = array();
26875                $uModel->read(array('currency_code'), $userId);
26876                $uModel->set(array('currency_code' => $currencyCode));
26877                $uModel->save();
26878                $this->log(__METHOD__ . ' Update to correct currency --> ' . $currencyCode . ' | userData -->' . json_encode($userData) . ' | kickback data --> ' . $dataJson, $logFileName);
26879            }
26880        }
26881
26882        // NC-5127: if family is withdrawn
26883        if ($formType == Configure::read('payment_credit_family_monthly_payment') && $this->memcache->get('deactivated-user-'.$userId)) {
26884            $msg = "User is withdrawn";
26885            $this->log(__METHOD__ . ' User is withdrawn. ' . json_encode($data), 'monthly_payment');
26886            throw new InternalErrorException($msg);
26887        }
26888
26889        # NC-8194: check null payment_plan_id and price_id
26890        if (
26891            (!isset($ptPaymentParams['paymentPlanId']) || $ptPaymentParams['paymentPlanId'] == null) ||
26892            (!isset($ptPaymentParams['priceId']) || $ptPaymentParams['priceId'] == null)
26893        ) {
26894            if ( $userData['User']['payment_plan_id'] && $userData['User']['price_id']) {
26895                $paymentPlanId = $userData['User']['payment_plan_id'];
26896                $priceId = $userData['User']['price_id'];
26897            } else {
26898                $defPlan = $this->PaymentPlanPrice->getDefaultPlan($userData['User']);
26899                $paymentPlanId = $defPlan['paymentPlanId'];
26900                $priceId = $defPlan['priceId'];
26901            }
26902
26903            $ptPaymentParams['paymentPlanId'] = $paymentPlanId;
26904            $ptPaymentParams['priceId'] = $priceId;
26905        }
26906
26907        $nativeOptionPayment = 0;
26908
26909        // if monthly payment, retry or force charge
26910        // check if user has receivable payment
26911        if (in_array($formType, array(
26912            Configure::read('payment_credit_monthly_payment'),
26913            Configure::read('payment_credit_force_charge'),
26914            Configure::read('payment_credit_retry'),
26915            Configure::read('payment_credit_family_monthly_payment')
26916        ))) {
26917            // compute receivable payments
26918            $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun);
26919
26920            // if has receivable payment
26921            // deduct said monthly settlement from the money sent to zeus
26922            if ($receivablePayment && $receivablePayment <= $amount) {
26923                // deduct from monthly payment
26924                $amount = $amount - $receivablePayment;
26925            }
26926
26927            // if has native speaker payments
26928            // deduct
26929            if (isset($ptPaymentParams['nativeOptionPayment']) && $ptPaymentParams['nativeOptionPayment'] > 0) {
26930                $nativeOptionPayment = $ptPaymentParams['nativeOptionPayment'];
26931                $amount -= $nativeOptionPayment;
26932            }
26933
26934            // compute appreciation receivable payments
26935            $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.appreciation'));
26936
26937            // if has receivable payment
26938            // deduct said monthly settlement from the money
26939            if ($appreciationReceivable && $appreciationReceivable <= $amount) {
26940                // deduct from monthly payment
26941                $amount = $amount - $appreciationReceivable;
26942            }
26943
26944            // compute live receivable payments
26945            $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.live'));
26946
26947            // if has receivable payment
26948            // deduct said monthly settlement from the money
26949            if ($liveLessonReceivable && $liveLessonReceivable <= $amount) {
26950                // deduct from monthly payment
26951                $amount = $amount - $liveLessonReceivable;
26952            }            
26953
26954        }
26955
26956        // Check receivables combine on `payment_credit_receivable` form type
26957        if( $formType == Configure::read('payment_credit_receivable') ) {
26958
26959            // compute appreciation receivable payments
26960            $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('appreciation_data.payment_element_type'));
26961
26962            // if has receivable payment
26963            // deduct said monthly settlement from the money
26964            if ($appreciationReceivable && $appreciationReceivable <= $amount) {
26965                // deduct from monthly payment
26966                $amount = $amount - $appreciationReceivable;
26967            }
26968
26969            // compute live receivable payments
26970            $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.live'));
26971
26972            if ($liveLessonReceivable && $liveLessonReceivable <= $amount) {
26973                // deduct from monthly payment
26974                $amount = $amount - $liveLessonReceivable;
26975            }            
26976
26977        }
26978
26979        // set transaction
26980        $dataSource = $uModel->getDataSource();
26981        $dataSource->begin();
26982
26983        // save settlement history for tracking
26984        $shData = array(
26985            'userId' => $userId,
26986            'params' => json_encode($data)
26987        );
26988
26989        if (!SettlementHistoryTable::add($shData)) {
26990            $msg = 'Saving user settlement history failed.';
26991            $this->log(__METHOD__ . ' ' . $msg . ' data --> ' . json_encode($shData) . ' | kickback data --> ' . $dataJson, $logFileName);
26992            $dataSource->rollback();
26993            // $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
26994            throw new InternalErrorException($msg);
26995        }
26996
26997        $this->loadModel("ContinuationCampaign");
26998
26999        switch($paymentStatusName) {
27000            case Configure::read('aftee.payment_status_authorised'):
27001
27002                $afteeParams = array(
27003                    'data' => $data,
27004                    'ptData' => $paymentTransactionData,
27005                    'logFileName' => $logFileName,
27006                    'dataSource' => $dataSource,
27007                    'amount' => $amount,
27008                    'userData' => $userData,
27009                    'cronDateRun' => $cronDateRun,
27010                    'receivablePayment' => $receivablePayment,
27011                    'appreciationReceivable' => $appreciationReceivable,
27012                    'liveLessonReceivable' => $liveLessonReceivable,
27013                    'transactionIdentifier' => $afteeTransactionIdentifier,
27014                    'aftee' => 1
27015                );
27016
27017                if( $formType == Configure::read('payment_credit_authentication') ) {
27018
27019                    //NJ-7548: fetch the user age $userData
27020                    $uAge = UserTable::getStudentAge($userData['User']['birthday']);
27021                    $uAge = $uAge ? (int) $uAge : null;
27022                    $showAppreciationFlg = 0;
27023
27024                    //change the show appreciation flg if no birthday set or 18 and above            
27025                    if (!$uAge || $uAge >= 18) {
27026                        $showAppreciationFlg = 1;
27027                    }
27028
27029                    // set user data
27030                    $uModel->clear();
27031                    $uModel->recursive = -1;
27032                    $userSet = array( 'allow_appreciation_flg' => 1 , 'show_appreciation_flg' => $showAppreciationFlg);
27033
27034                    // set child card expiration date same as parent
27035                    if (isset($ptPaymentParams['family_data']['applyPlan']['card_expiration_date'])) {
27036                        $userSet['card_expiration_date'] = $ptPaymentParams['family_data']['applyPlan']['card_expiration_date'];
27037                    }
27038
27039                    $uModel->read(array_keys($userSet), $userId);
27040                    $uModel->set($userSet);
27041                    $uModel->validate = array();
27042                    if (!$uModel->save()) {
27043                        $msg = 'Updating user failed.';
27044                        $this->log(__METHOD__ . ' ' . $msg . ' data --> ' . json_encode($userSet) . ' | kickback data --> ' . $dataJson, $logFileName);
27045                        $dataSource->rollback();
27046                        // $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
27047                        throw new InternalErrorException($msg);
27048                    }
27049
27050                }
27051                // NJ-24425: release secured budget upon changing payment method FROM old AFTEE to new AFTEE number
27052                if ($formType == Configure::read('payment_credit_change')  
27053                    && !empty($userData['User']['card_token']) && !empty($userData['User']['aftee_transaction_identifier'])
27054                ) {
27055                    // check if user is still Free (no monthly payment made yet)
27056                    if ($userData['User']['payment_plan_id'] == Configure::read('payment_plans.free_trial')) {
27057                        if (!class_exists('AfteePaymentService')) {
27058                            App::uses('AfteePaymentService','Lib');
27059                        }
27060                        $afteeService = new AfteePaymentService();
27061                        $checkRes = $afteeService->refund($userData, 'Change Payment Method');
27062                        $this->log( '[NJ-24425] ' . json_encode($checkRes), 'aftee_debug');
27063                        if ( !array_key_exists("object", $checkRes) || (isset($checkRes['object']) && $checkRes['object'] == 'error')) {
27064                            $msg = '[Aftee] Failed to release secured budget';
27065                            $this->log(__METHOD__ . ' ' . $msg . ' User data --> ' . json_encode($userData) . ' | refundData --> ' . $checkRes, 'aftee_debug');
27066                        }
27067                    }
27068                }
27069                return $this->processAfteePayment($afteeParams);
27070            case Configure::read('aftee.payment_status_error'):
27071                switch ($formType) {
27072                    case Configure::read('payment_credit_family_monthly_payment'):
27073                    case Configure::read('payment_credit_monthly_payment'):
27074                        // set user data
27075                        $uModel->clear();
27076                        $uModel->recursive = -1;
27077                        $userSet = array(
27078                            'fail_flg' => 1,
27079                            'counseling_attended_flg' => 1,
27080                            'charge_flg' => 0,
27081                            'show_appreciation_flg' =>  0,
27082                            'allow_appreciation_flg' => 0,
27083                            'native_option' => 0,
27084                            'next_charge_date' => null,
27085                            'modified' => date('Y-m-d H:i:s')
27086                        );
27087
27088                        if (isset($userData['User']['native_option']) && $userData['User']['native_option']) {
27089                            $userSet['native_option_cancellation_time'] = date('Y-m-d H:i:s');
27090                        }
27091
27092                        $uModel->read(array_keys($userSet), $userId);
27093                        $memoStr = date('Y/m/d H:i:s')." Cancellation of Native Speaker Unlimited option";
27094                        $updatedMemo = $memoStr."\n".$userData['User']['memo'];
27095                        $userSet['memo'] = $updatedMemo;
27096
27097                        $uModel->set($userSet);
27098                        $uModel->validate = array();
27099                        if (!$uModel->save()) {
27100                            $msg = 'Updating user failed.';
27101                            $this->log(__METHOD__ . ' ' . $msg . ' data --> ' . json_encode($userSet) . ' | kickback data --> ' . $dataJson, $logFileName);
27102                            $dataSource->rollback();
27103                            // $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
27104                            throw new InternalErrorException($msg);
27105                        }
27106
27107                        //NJ-2814 add logs
27108                        if (isset($ptPaymentParams['nativeOptionJoin']) && $ptPaymentParams['nativeOptionJoin']) {
27109                            $nativeStatus = 1; // subscribed
27110                            $statusBefore = $option_before_name = '';
27111                        } else {
27112                            $nativeStatus = 3; // unsubscribed
27113                            $statusBefore = 1;
27114                            $option_before_name = 'Native Unlimited Option';
27115                        }
27116
27117                        $optionLogParams = array(
27118                            'user_id' => $userId,
27119                            'platform' => $ptPaymentParams['platform'],
27120                            'status' => $nativeStatus,
27121                            'controller_name' => $this->request->params['controller'],
27122                            'action_name' => $this->request->params['action'],
27123                            'user_type' => 0, // user
27124                            'option_before' => $statusBefore,
27125                            'option_after' => 1,
27126                            'option_before_name' => $option_before_name,
27127                            'option_after_name' => '',
27128                            'payment_plan_id' => $paymentPlanId
27129                        );
27130
27131                        ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
27132
27133                        // update user who join in ContinuationCampaign to fail status - 3
27134                        if ($this->ContinuationCampaign->setFailedUser(array('user_id' => $userId))) {
27135                            $msg = 'Failed to update ContinuationCampaign status to 3.';
27136                            $this->log(__METHOD__ . ' ' . $msg . ' data --> ' . json_encode(array('user_id' => $userId)) . ' | kickback data --> ' . $dataJson, $logFileName);
27137                            $dataSource->rollback();
27138                            // $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
27139                            throw new InternalErrorException($msg);
27140                        }
27141
27142                        // Get children list
27143                        $childList = $uModel->getChildId($userId);
27144
27145                        // check if user is parent 
27146                        if (!empty($childList)) {
27147                            foreach ($childList as $childId) {
27148                                // get child detail
27149                                $familyMember = $uModel->find('first', array(
27150                                    'fields' => array(
27151                                        'User.id',
27152                                        'User.memo',
27153                                        'User.parent_id',
27154                                        'User.native_option'
27155                                    ),
27156                                    'conditions' => array('User.id' => $childId)
27157                                ));
27158                                $familyObj = new UserTable($familyMember['User']);
27159                                $addMemo = 'Family plan[User]: family deactivation parent failed settlement';
27160                                unset($familyObj->parent_id);
27161
27162                                // update children status to free
27163                                if ($this->User->updateStatusToFree($familyObj, $addMemo)) {
27164                                    // - deactivate reserved lessons of the children
27165                                    $this->LessonSchedule->deactivateDisableReservedLessons($childId, true, false, true, null, false, true);
27166
27167                                    // NC-8645: add deactivation lock
27168                                    UserTable::saveUserDeactivationLock($childId);
27169
27170                                    // NC-5342: add deactivation log
27171                                    $this->loadModel('FamilyDeactivationLog');
27172                                    $this->FamilyDeactivationLog->addLog($childId);
27173                                }
27174
27175                                $switchAccountParams = array(
27176                                    'parentId' => $userId,
27177                                    'userId' => $childId
27178                                );
27179                                // delete switch account data
27180                                $this->UsersFamilyAccount->removeSwitchAccount($switchAccountParams);
27181                            }
27182                        }
27183
27184                        if ($nativeOptionPayment > 0) {
27185                            $paymentNOData = array(
27186                                'user_id' => $userId,
27187                                'type_id' => $typeId,
27188                                'pay_kbn' => 1,
27189                                'form_type' => Configure::read('payment_native_option_monthly_payment'),
27190                                'reference_id' => $userId,
27191                                'amount' => $nativeOptionPayment,
27192                                'ordd' => $orderCode,
27193                                'card_company' => $cardCompany,
27194                                'param1' => $dataJson,
27195                                'param2' => 'error: aftee',
27196                                'transaction_code' => $orderCode,
27197                                'currency_code' => $currencyCode,
27198                                'payment_plan_id' => isset($ptPaymentParams['paymentPlanId']) ? $ptPaymentParams['paymentPlanId'] : null,
27199                                'price_id' => isset($ptPaymentParams['priceId']) ? $ptPaymentParams['priceId'] : null,
27200                                'payment_type' => isset($ptPaymentParams['paymentType']) ? $ptPaymentParams['paymentType'] : null,
27201                                'discounted_amount' => isset($ptPaymentParams['discounted_amount']) ? $ptPaymentParams['discounted_amount'] : 0
27202                            );
27203
27204                            // set payment model
27205                            $pModel = $this->Payment;
27206                            $pModel->clear();
27207                            $pModel->create();
27208                            $pModel->recursive = -1;
27209                            $pModel->set($paymentNOData);
27210                            $pModel->validate = array();
27211
27212                            if (!$pSave = $pModel->save()) {
27213                                $msg = 'Saving payment failed.';
27214                                $this->log(__METHOD__ . ' ' . $msg . ' data --> ' . json_encode($paymentNOData) . ' | kickback data --> ' . $dataJson, $logFileName);
27215                                $dataSource->rollback();
27216                                // $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
27217                                throw new InternalErrorException($msg);
27218                            }
27219                        }
27220                    case Configure::read('payment_credit_receivable'):
27221                    case Configure::read('payment_credit_retry'):
27222                    case Configure::read('payment_credit_force_charge'):
27223                        $paymentData = array(
27224                            'user_id' => $userId,
27225                            'type_id' => $typeId,
27226                            'pay_kbn' => 1,
27227                            'form_type' => $formType,
27228                            'reference_id' => $userId,
27229                            'amount' => $amount,
27230                            'ordd' => $orderCode,
27231                            'card_company' => $cardCompany,
27232                            'param1' => $dataJson,
27233                            'param2' => 'error: aftee',
27234                            'transaction_code' => $orderCode,
27235                            'currency_code' => $currencyCode,
27236                            'payment_plan_id' => isset($ptPaymentParams['paymentPlanId']) ? $ptPaymentParams['paymentPlanId'] : null,
27237                            'price_id' => isset($ptPaymentParams['priceId']) ? $ptPaymentParams['priceId'] : null,
27238                            'payment_type' => isset($ptPaymentParams['paymentType']) ? $ptPaymentParams['paymentType'] : null,
27239                            'discounted_amount' => isset($ptPaymentParams['discounted_amount']) ? $ptPaymentParams['discounted_amount'] : 0
27240                        );
27241
27242                        // set payment model
27243                        $pModel = $this->Payment;
27244                        $pModel->clear();
27245                        $pModel->create();
27246                        $pModel->recursive = -1;
27247                        $pModel->set($paymentData);
27248                        $pModel->validate = array();
27249
27250                        if (!$pSave = $pModel->save()) {
27251                            $msg = 'Saving payment failed.';
27252                            $this->log(__METHOD__ . ' ' . $msg . ' data --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, $logFileName);
27253                            $dataSource->rollback();
27254                            // $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
27255                            throw new InternalErrorException($msg);
27256                        }
27257                    case Configure::read('payment_credit_authentication'):
27258                    case Configure::read('payment_credit_change'):
27259                        $ptUpdate = $this->updatePaymentTransaction(array(
27260                            'id' => $paymentTransactionData['id'],
27261                            'fields' => array(
27262                                'status' => 2, // error
27263                                'payment_id' => isset($pSave['Payment']['id']) ? $pSave['Payment']['id'] : null,
27264                                'response_text' => array('aftee_kickback' => json_decode($dataJson, true))
27265                            ),
27266                            'logFileName' => $logFileName
27267                        ));
27268
27269                        if (!$ptUpdate) {
27270                            $dataSource->rollback();
27271                            $msg = 'Updating payment transaction failed.';
27272                            $this->log(__METHOD__ . ' ' . $msg . ' data --> ' . json_encode(array('pt_id' => $paymentTransactionData['id'])) . ' | kickback data --> ' . $dataJson, $logFileName);
27273                            // $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
27274                            throw new InternalErrorException($msg);
27275                        }
27276                        break;
27277                }
27278                $dataSource->commit();
27279                break;
27280            default:
27281                $this->log(__METHOD__ . ' No data save', $logFileName);
27282                break;
27283        }
27284        $response['success'] = true;
27285        return json_encode($response);
27286    }
27287
27288    /**
27289     * Aftee Modal Direct Payment outside membership
27290     * Save payment data for coin, native option, ebook
27291     * handle payment transaction success from aftee modal
27292     */
27293    public function handleAfteeDirectPaymentSuccess(){
27294        $this->autoRender = $this->autoLayout = false;
27295        $logFileName = isset($this->request->data['logFileName']) ? $this->request->data['logFileName'] : 'debug';
27296        $ncTerminalType = isset($this->request->data['ncTerminalType']) ? $this->request->data['ncTerminalType'] : 1;
27297        $response = array();
27298
27299        // get post data
27300        if ($this->request->is('post')) {
27301            $rawData = $data = $this->request->data;
27302        }
27303
27304        // if empty data
27305        if ( !isset($data) || !isset($data['success']) || 
27306            !isset($data['success']['authorization_result']) || 
27307            !isset($data['logFileName']) ||
27308            !isset($data['apiToken']) ||
27309            !isset($data['formType']) ||
27310            !isset($data['successUrl']) ||
27311            !isset($data['memKeyError']) ||
27312            !isset($data['referrer']) ||
27313            (
27314                empty(trim($data['apiToken'])) &&
27315                $data['apiToken'] !== 0 &&
27316                $data['apiToken'] !== '0'
27317            )
27318        ) {
27319            $this->log(__METHOD__ . ' Missing parameters. post data --> ' . json_encode($data), 'error');
27320            throw new BadRequestException("Missing parameter(s).");
27321        }
27322
27323        // merge post data
27324        $successData = $data['success'];
27325        $successData['authentication_token'] = $data['authentication_token'];
27326        $data = $successData;    
27327
27328        // set variables
27329        $orderCode = isset($data['shop_transaction_no']) && !empty($data['shop_transaction_no']) ? $data['shop_transaction_no'] : NULL;
27330        $data['OrderCode'] = $orderCode;
27331        $paymentStatusName = isset($data['authorization_result']) && !empty($data['authorization_result']) ? $data['authorization_result'] : '';
27332        $dataJson = json_encode($data);
27333        $device = myTools::getDevice();
27334        if ($ncTerminalType == Configure::read('nc_terminal_type.pc')) {
27335            if ($device != 1) {
27336                $device = 6; // sp
27337            }
27338        }
27339
27340        // get payment transaction data 
27341        $paymentTransactionData = $this->PaymentTransaction->getAfteePaymentTransaction($orderCode);
27342        $pt = $paymentTransactionData;
27343
27344        // return if payment transaction does not exist
27345        if (!$paymentTransactionData) {
27346            $msg = 'Payment transaction does not exist.';
27347            $this->log(__METHOD__ . ' ' . $msg . ' kickback data -->' . $dataJson, 'aftee_debug');
27348            throw new InternalErrorException($msg);
27349        }
27350
27351        if (!isset($paymentTransactionData['user_id'])) {
27352            $msg = ' array key user_id does not exist.';
27353            $this->log(__METHOD__ . ' ' . $msg . ' kickback data -->' . $dataJson, 'aftee_debug');
27354            throw new InternalErrorException($msg);
27355            exit;
27356        }
27357
27358        // set variables
27359        $userId = $paymentTransactionData['user_id'];
27360        $cardCompany = Configure::read('card_company.aftee');
27361        $ptPaymentParams = json_decode($paymentTransactionData['payment_params'], true);
27362        $logFileName = isset($ptPaymentParams['logFileName']) ? $ptPaymentParams['logFileName'] : 'debug';
27363        $currencyCode = isset($ptPaymentParams['currencyCode']) ? $ptPaymentParams['currencyCode'] : '';
27364        $formType = $ptPaymentParams['formType'];
27365        $familyId = isset($ptPaymentParams['familyId']) ? $ptPaymentParams['familyId'] : null;
27366        $userId = $familyId ? $familyId : $userId;
27367
27368        //remove user from currently paying users
27369        UserTable::removePayingUserFromMemcache($userId);
27370
27371        if (!isset($ptPaymentParams['paymentAmount'])) {
27372            $msg = 'Payment amount in payment transaction does not exist.';
27373            $this->log(__METHOD__ . ' ' . $msg . ' kickback data -->' . $dataJson . ' - ' . json_encode($ptPaymentParams), 'error');
27374            throw new InternalErrorException($msg);
27375            exit;
27376        }
27377
27378        $amount = $ptPaymentParams['paymentAmount'];
27379
27380        // set user model
27381        $uModel = $this->User;
27382
27383        // get user data
27384        $user = $uModel->find('first', array(
27385            'fields' => array(
27386                'status',
27387                'nickname',
27388                'email',
27389                'hash',
27390                'memo',
27391                'parent_id',
27392                'next_charge_date',
27393                'complimentary_code',
27394                'payment_plan_id',
27395                'monthly_speaking_attended_flg',
27396                'monthly_speaking_business_attended_flg',
27397                'id',
27398                'hash16',
27399                'currency_code',
27400                'native_language2',
27401                'charge_flg',
27402                'fail_flg',
27403                'double_check_flg',
27404                'birthday',
27405                'native_option',
27406                'phone_number',
27407                'callan_first_name',
27408                'callan_last_name',
27409                'callan_gender'
27410            ),
27411            'conditions' => array('id' => $userId),
27412            'recursive' => -1
27413        ));
27414        
27415
27416        // return if user does not exist
27417        if (!$user) {
27418            $msg = "User does not exist";
27419            $this->log(__METHOD__ . ' User does not exist. payment transaction data --> ' . json_encode($paymentTransactionData) . ' | kickback data --> ' . $dataJson, $logFileName);
27420            throw new InternalErrorException($msg);
27421        }
27422
27423        $userData = $user['User'];
27424
27425
27426        switch ($formType) {
27427            case Configure::read('payment_credit_coin_purchase'):
27428                $money = $amount;
27429                $points = isset($ptPaymentParams['coinPurchasePoints']) ? $ptPaymentParams['coinPurchasePoints'] : 0;
27430                $couponAmount = isset($ptPaymentParams['discounted_amount']) ? $ptPaymentParams['discounted_amount'] : 0;
27431                $paymentPlanId = isset($ptPaymentParams['paymentPlanId']) ? $ptPaymentParams['paymentPlanId'] : '';
27432                $priceId = isset($ptPaymentParams['priceId']) ? $ptPaymentParams['priceId'] : '';
27433                $paymentType = Configure::read('payment_types.coin');
27434                $coinPurchaseWithCoupon = false;
27435                if ($paymentStatusName == Configure::read('aftee.payment_status_authorised')) {
27436                    
27437                    if (!class_exists('myMemcached')) {
27438                        App::uses('myMemcached', 'Lib');
27439                    }
27440                    $memcached = new myMemcached();
27441                    
27442                    //check if coupon requests is processed already
27443                    $isCouponRequestId = $memcached->get('aftee_coupon_used_' . $userId);
27444
27445                    // if using coupon
27446                    $couponReqID = null;
27447                    if(isset($isCouponRequestId['success']) && $isCouponRequestId['success']) {
27448                        $couponReqID = isset($isCouponRequestId['grp_id']) ? $isCouponRequestId['grp_id'] : null;
27449                        $coinPurchaseWithCoupon = true;
27450                        $memcached->delete('aftee_coupon_used_' . $userId);
27451                    } else {
27452                        if ($couponAmount > 0) {
27453                            $couponData = array(
27454                                'userId' => $userId,
27455                                'kbn' => isset($ptPaymentParams['coin_event']) ? $ptPaymentParams['coin_event'] : Configure::read('coupon_kbn.coin_purchase'),
27456                                'useCouponAmount' => isset($ptPaymentParams['coin_useCouponAmount']) ? $ptPaymentParams['coin_useCouponAmount'] : 0,
27457                                'nextChargeDate' => date('Y-m-d'),
27458                                'request_result' => true
27459                            );
27460                            // TEMPLATE
27461                            $result_coupon_use = $this->UsersCouponV1->performCouponUse($couponData);
27462                            $result_coupon_use = !empty($result_coupon_use) ? json_decode($result_coupon_use,true) : array();
27463                            if(empty($result_coupon_use)) {
27464                                $this->log(__METHOD__ . ' failed to update coupon data. --> ' . json_encode($couponData) . ' user id --> ' . json_encode($userData['id']), 'error');
27465                                $msg = Configure::read('Coin purchased failed');
27466                                throw new InternalErrorException($msg);
27467                                exit;
27468                            }
27469
27470                            if (isset($result_coupon_use['cgrp_id'])) {
27471                                $coinPurchaseWithCoupon = true;
27472                                $couponReqID = $result_coupon_use['cgrp_id'];
27473                            }
27474                        }
27475                    }
27476
27477                    $referenceId = (isset($userData['parent_id']) && !empty($userData['parent_id'])) ? $userData['parent_id'] : $userId;
27478                    $coinPurchasePoints = intVal($points);
27479                    $coinData = $this->UsersPoint->SET_charge_overseas_menue($coinPurchasePoints, $currencyCode);
27480
27481                    // NC-5007 add to the user's existing coin
27482                    $pcAfteeParams = array(
27483                        'userId' => $userId,
27484                        'point' => $coinData['num_of_coin'] - $coinData['bonus_coin'],
27485                        'kbn' => 7,
27486                        'kbnType' => 1, // add coin
27487                        'coinType' => 1, // purchase coin
27488                        'coinFailMessage' => Configure::read('coin.failed.buy_coin'),
27489                        'device' => $device
27490                    );
27491
27492                    $scAfteeParams = array(
27493                        'userId' => $userId,
27494                        'point' => $coinData['bonus_coin'],
27495                        'kbn' => 7,
27496                        'kbnType' => 1, // add coin
27497                        'coinType' => 2, // service coin
27498                        'coinFailMessage' => Configure::read('coin.failed.buy_coin'),
27499                        'device' => $device
27500                    );
27501
27502                    $pointParams = [$pcAfteeParams, $scAfteeParams];
27503
27504                    if ( $pointParams ) {
27505                        foreach($pointParams as $key => $val) {
27506                            if (!$this->UsersPoint->performPointTransaction($val)) {
27507                                $this->log(__METHOD__ . ' Failed to add user point. ' . json_encode($val) . ' --> ' . json_encode($paymentTransactionData), 'error');
27508                                $msg = Configure::read('Coin purchased failed');
27509                                throw new InternalErrorException($msg);
27510                                exit;
27511                            }
27512                        }
27513                    }
27514                    
27515                    $paymentData = array(
27516                        'user_id' => $userId,
27517                        'amount' => $money,
27518                        'status' => 1,
27519                        'reference_id' => $referenceId,
27520                        'payment_transaction_password' => $pt['password'],
27521                        'card_company' => Configure::read('card_company.aftee'),
27522                        'param1' => json_encode($data),
27523                        'form_type' => $formType,
27524                        'ordd' => $orderCode,
27525                        'transaction_code' => $orderCode,
27526                        'currency_id' => Configure::read('default.settlement_currency_id'), // set currency id to jpy
27527                        'currency_code' => $currencyCode,
27528                        'payment_id' => $paymentPlanId,
27529                        'price_id' => $priceId,
27530                        'payment_type' => $paymentType,
27531                        'discounted_amount' => $couponAmount,
27532                        'coupon_request_id' => $couponReqID,
27533                        'type_id' => 1
27534                    );
27535
27536                    // create new payment
27537                    $this->Payment->clear();
27538                    $this->Payment->create();
27539                    $this->Payment->set($paymentData);
27540                    $this->Payment->validate = array();
27541
27542                    // check if payment was not saved
27543                    if (!$this->Payment->save()) {
27544                        $this->log(__METHOD__ . ' Failed to save payment data. ' . json_encode($paymentData) . ' -- ' . json_encode($data), $logFileName);
27545
27546                        if($coinPurchaseWithCoupon) {
27547                            $couponUnconfirmData = array(
27548                                'grpId' => $paymentData['coupon_request_id'],
27549                                'userId' => $userId,
27550                                'kbn' => Configure::read('coupon_kbn.coin_purchase')
27551                            );
27552                            $result_coupon_unconfirm = $this->UsersCouponV1->performCouponUnconfirm($couponUnconfirmData);
27553                            
27554                            if (empty($result_coupon_unconfirm)) {
27555                                $this->log(__METHOD__ . ' failed to perform coupon unconfirm data. '. json_encode($couponUnconfirmData), 'error');
27556                            }
27557                        }
27558
27559                        $msg = 'Coin purchased failed';
27560                        throw new InternalErrorException($msg);
27561                        exit;
27562                    }
27563
27564                    //update/add user`s settlement amount
27565                    $this->User->updateUserPayments($paymentData);
27566
27567                    // update payment transaction
27568                    $updateData = array(
27569                        'id' => $pt['id'],
27570                        'fields' => array(
27571                            'status' => 1,
27572                            'response_text' => array('aftee_directPayment_response' => $data))
27573                    );
27574
27575                    // update payment transaction
27576                    if (!$this->PaymentTransaction->updateAfteePaymentTransaction($updateData)) {
27577                        $this->log(__METHOD__ . ' Failed to save payment data. ' . json_encode($paymentData) . ' -- ' . json_encode($data), $logFileName);
27578                        $msg = Configure::read('Coin purchased failed');
27579                        throw new InternalErrorException($msg);
27580                    }
27581                    
27582                } else if ($paymentStatusName ==  Configure::read('aftee.payment_status_error')) {
27583                    $afteeParams = array(
27584                        'ptId' => $pt['id'],
27585                        'afteeData' => array('aftee_directpayment_response' => $data),
27586                        'userId' => $userId,
27587                        'money' => $money,
27588                        'formType' => $formType,
27589                        'priceId' => $priceId,
27590                        'paymentId' => $paymentPlanId,
27591                        'paymentType' => $paymentType,
27592                        'currency' => $currencyCode
27593                    );
27594                    $this->Payment->afteeSaveFailedSettlement($afteeParams);
27595                    $this->log(__METHOD__ . ' Failed to save payment data. ' . json_encode($paymentData) . ' -- ' . json_encode($data), $logFileName);
27596                    $msg = Configure::read('Coin purchased failed');
27597                    throw new InternalErrorException($msg);
27598                }
27599                break;
27600            case Configure::read('payment_credit_textbook_purchase'):
27601                $money = isset($ptPaymentParams['money']) ? $ptPaymentParams['money'] : 0;
27602                $discounted_amount = isset($ptPaymentParams['discounted_amount']) ? $ptPaymentParams['discounted_amount'] : 0;
27603                $formType = Configure::read('payment_credit_textbook_purchase');
27604                $paymentType = Configure::read('payment_types.textbook_purchase');
27605                if ($paymentStatusName == Configure::read('aftee.payment_status_authorised')) {
27606                    $textbookItems = isset($ptPaymentParams['textbookItems']) ? $ptPaymentParams['textbookItems'] : array();
27607                    $subTotal = isset($ptPaymentParams['subTotal']) ? $ptPaymentParams['subTotal'] : '';
27608                    $textbook_sales_id = isset($rawData['textbook_sales_id']) ? $rawData['textbook_sales_id'] : '';
27609                    $referenceId = isset($userData['parent_id']) && !empty($userData['parent_id']) ? $userData['parent_id'] : $userData['id'];
27610                    $paymentData = array(
27611                        'user_id' => $userData['id'],
27612                        'amount' => $money,
27613                        'status' => 1,
27614                        'reference_id' => $referenceId,
27615                        'payment_transaction_password' => $pt['password'],
27616                        'card_company' => Configure::read('card_company.aftee'),
27617                        'param1' => json_encode($data),
27618                        'form_type' => $formType,
27619                        'ordd' => $orderCode,
27620                        'transaction_code' => $orderCode,
27621                        'currency_id' => Configure::read('default.settlement_currency_id'), // set currency id to jpy
27622                        'currency_code' => $userData['currency_code'],
27623                        'payment_id' => $userData['payment_plan_id'],
27624                        'price_id' => $userData['price_id'],
27625                        'payment_type' => $paymentType,
27626                        'type_id' => 1,
27627                        'discounted_amount' => $discounted_amount
27628                    );
27629            
27630                    // create new payment
27631                    $this->Payment->clear();
27632                    $this->Payment->create();
27633                    $this->Payment->set($paymentData);
27634                    $this->Payment->validate = array();
27635            
27636                    // check if payment was not saved
27637                    if (!$this->Payment->save()) {
27638                        $this->log(__METHOD__ . ' Failed to save payment data. ' . json_encode($paymentData), $logFileName);
27639                        $msg = 'failed_to_save_payment_data';
27640                        throw new InternalErrorException($msg);
27641                    }
27642            
27643                    //update/add user`s settlement amount
27644                    $this->User->updateUserPayments($paymentData);
27645            
27646                    $textbookSales = $this->TextbookSale->find('first', array(
27647                        'conditions' => array('TextbookSale.sales_code' => $pt['password']),
27648                        'recursive' => -1
27649                    ));
27650            
27651                    // if has textbook sales, update payment_id
27652                    if ($textbookSales) {
27653                        $this->TextbookSale->clear();
27654                        if (!$this->TextbookSale->read(null, $textbookSales['TextbookSale']['id'])) {
27655                            $this->log(__METHOD__ . ' Textbook sales id does not exist. ' . json_encode($textbookSales), $logFileName);
27656                            $msg = 'textbook_sales_id_does_not_exist';
27657                            throw new InternalErrorException($msg);
27658                        }
27659            
27660                        $this->TextbookSale->set('payment_id', $this->Payment->id);
27661                        $this->TextbookSale->set('payment_status', 1);
27662                        if (!$this->TextbookSale->save()) {
27663                            $this->log(__METHOD__ . ' Failed update textbook sales payment status to 1. ' . json_encode($textbookSales), $logFileName);
27664                            $msg = 'failed_update_textbook_sales_payment_status_to_1';
27665                            throw new InternalErrorException($msg);
27666                        }
27667                    }
27668
27669                    // update payment transaction
27670                    $updateData = array(
27671                        'id' => $pt['id'],
27672                        'fields' => array(
27673                            'status' => 1,
27674                            'response_text' => array('aftee_directPayment_response' => $data))
27675                    );
27676
27677                    // update payment transaction
27678                    if (!$this->PaymentTransaction->updateAfteePaymentTransaction($updateData)) {
27679                        $this->log(__METHOD__ . ' Failed to save payment data. ' . json_encode($paymentData) . ' -- ' . json_encode($data), $logFileName);
27680                        $msg = Configure::read('Coin purchased failed');
27681                        throw new InternalErrorException($msg);
27682                    }
27683                    
27684                    // on sucess send email
27685                    // and send to slack
27686
27687                    // get items
27688                    $cartItems = array();
27689                    $totalCartItems = count($textbookItems);
27690                    $countNatGeoEbookItems = 0;
27691                    // loop through items
27692                    foreach ($textbookItems as $cart) {
27693                        if(!empty($cart['title'])) {
27694                            $cartIds[] = $cart['id'];
27695                            $cartItems[] = $cart['title'];
27696
27697                            //NC-7469 for nat geo ebbok items
27698                            if ($cart['category_id'] == Configure::read('national_geographic_ebook')) {
27699                                $countNatGeoEbookItems += 1;
27700                            }
27701                        }
27702                    }
27703
27704                    // NJ-18619: update add to cart status
27705                    if ($textbookItems) {
27706                        $this->TextbookSalesAddToCartItem->clear();
27707                           $conditions = array(
27708                               'TextbookSalesAddToCartItem.user_id' => $userData['id'],
27709                               'TextbookSalesAddToCartItem.status' => 1
27710                           );
27711                        $this->TextbookSalesAddToCartItem->updateAll(
27712                            array(
27713                                'TextbookSalesAddToCartItem.status' => 0
27714                            ),
27715                            $conditions
27716                        );
27717                    }
27718
27719                    $post['totalNatGeoEbookItems'] = $countNatGeoEbookItems;
27720
27721                    // get genders
27722                    $callanGender = Configure::read('gender_types');
27723
27724                    // set template id for email sending
27725                    $post['templateId'] = Configure::read('site_in_mail.student_ebook_purchase_complete');
27726                    
27727                    $post['genderKey'] = $userData['callan_gender'];
27728                    $post['gender'] = isset($callanGender[$userData['callan_gender']]) ? $callanGender[$userData['callan_gender']] : ''; // change gender to human readable format
27729
27730                    $post['name'] = $userData['callan_first_name'];
27731                    $post['lastname'] = $userData['callan_last_name'];
27732                    $post['email'] = $userData['email'];
27733                    $post['userId'] = $userData['id'];
27734
27735                    // order info
27736                    $post['items'] = $cartItems;
27737                    $post['subtotal'] = $subTotal;
27738                    $post['total'] = $money;
27739
27740                    // add url
27741                    $post['url'] = myTools::getUrl() . '/admin/textbook_ebook-sales?id='.$textbook_sales_id;
27742
27743                    // set slack username
27744                    $post['slackUsername'] = "Ebook Purchase";
27745                    $post['invalid_email_flg'] = $userData['invalid_email_flg'];
27746
27747                    // set additional slack info (NJ-36233)
27748                    $post['currency_code'] = $userData['currency_code'];
27749                    $post['native_language'] = $userData['native_language2'];
27750
27751                    // send email
27752                    $sendEmailSlack = $this->sendEbookPurchaseEmailSlack($post, $userData);
27753
27754                } else if ($paymentStatusName ==  Configure::read('aftee.payment_status_error')) {
27755                    $afteeFailParams = array(
27756                        'ptId' => $pt['id'],
27757                        'afteeData' => array('aftee_directpayment_response' => $data),
27758                        'userId' => $userData['id'],
27759                        'money' => $money,
27760                        'formType' => $formType,
27761                        'priceId' => $userData['price_id'],
27762                        'paymentId' => $userData['payment_plan_id'],
27763                        'paymentType' => $paymentType,
27764                        'currency' => $userData['currency_code']
27765                    );
27766            
27767                    $this->log(__METHOD__ . ' aftee error --> ' . json_encode($data), $logFileName);
27768                    $this->Payment->afteeSaveFailedSettlement($afteeFailParams);
27769                    return array('error' => true, 'message' => 'aftee_create_order_error');
27770                }
27771                break;
27772            case Configure::read('payment_native_option_join'):
27773                $initialAmount = $amount;
27774                $sendId = isset($ptPaymentParams['sendId']) ? $ptPaymentParams['sendId'] : $userData['id'];
27775                $discounted_amount = isset($ptPaymentParams['discounted_amount']) ? $ptPaymentParams['discounted_amount'] : 0;
27776                $paymentType = Configure::read('payment_types.native_option');
27777                if ($paymentStatusName == Configure::read('aftee.payment_status_authorised')) {
27778                    $paymentData = array(
27779                        'user_id' => $userData['id'],
27780                        'amount' => $initialAmount,
27781                        'status' => 1,
27782                        'reference_id' => $sendId,
27783                        'payment_transaction_password' => $pt['password'],
27784                        'card_company' => $cardCompany,
27785                        'param1' => json_encode($data),
27786                        'form_type' => $formType,
27787                        'ordd' => $orderCode,
27788                        'transaction_code' => $orderCode,
27789                        'currency_id' => Configure::read('default.settlement_currency_id'), // set currency id to jpy
27790                        'currency_code' => $userData['currency_code'],
27791                        'price_id' => $userData['price_id'],
27792                        'payment_id' => $userData['payment_plan_id'],
27793                        'payment_type' => $paymentType,
27794                        'type_id' => 1,
27795                        'discounted_amount' => $discounted_amount
27796                    );
27797
27798                    // create new payment
27799                    $this->Payment->clear();
27800                    $this->Payment->create();
27801                    $this->Payment->set($paymentData);
27802                    $this->Payment->validate = array();
27803
27804                    // check if payment was not saved
27805                    if (!$this->Payment->save()) {
27806                        $this->log(__METHOD__ . ' Failed to save payment data. ' . json_encode($paymentData) . ' -- ' . json_encode($data), $logFileName);
27807                        $msg = 'Failed to save payment data';
27808                        throw new InternalErrorException($msg);
27809                    }
27810
27811                    // update native option to 1
27812                    $this->User->userNativeOptionProcess(array('user_id' => $userData['id'], 'type' => 'on'));
27813                    //NJ-2814 add logs
27814                    $optionLogParams = array(
27815                        'user_id' => $userData['id'],
27816                        'platform' => $ncTerminalType,
27817                        'status' => 1, // Join/Subscribed
27818                        'controller_name' => 'Payment',
27819                        'action_name' => 'handleAfteeDirectPaymentSuccess',
27820                        'user_type' => 0, // user
27821                        'option_before' => '',
27822                        'option_after' => 1,
27823                        'option_before_name' => '',
27824                        'option_after_name' => 'Native Unlimited Option',
27825                        'payment_plan_id' => $userData['payment_plan_id']
27826                    );
27827
27828                    ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
27829
27830                    // - save registration status step
27831                    $stepKey = Configure::read('registration_steps.user_info_entry');
27832                    $this->saveStep($userData['id'], $stepKey);
27833
27834                    //update/add user`s settlement amount
27835                    $this->User->updateUserPayments($paymentData);
27836
27837                    // update payment transaction
27838                    $updateData = array(
27839                        'id' => $pt['id'],
27840                        'fields' => array(
27841                            'status' => 1,
27842                            'response_text' => array('aftee_directPayment_response' => $data))
27843                    );
27844
27845                    // update payment transaction
27846                    if (!$this->PaymentTransaction->updateAfteePaymentTransaction($updateData)) {
27847                        $this->log(__METHOD__ . ' Failed to update payment transaction' . json_encode($updateData), $logFileName);
27848                        $msg = 'Failed to update payment transaction';
27849                        throw new InternalErrorException($msg);
27850                    }
27851                } else if ($paymentStatusName ==  Configure::read('aftee.payment_status_error')) {
27852                    // aftee payment params
27853                    $afteeParams = array(
27854                        'ptId' => $pt['id'],
27855                        'afteeData' => $data,
27856                        'userId' => $userData['id'],
27857                        'money' => $initialAmount,
27858                        'formType' => $formType,
27859                        'priceId' => $userData['price_id'],
27860                        'paymentId' => $userData['payment_plan_id'],
27861                        'paymentType' => $paymentType,
27862                        'currency' => $userData['currency_code']
27863                    );
27864                    $this->Payment->afteeSaveFailedSettlement($afteeParams);
27865                    $msg = 'Join Native Option Failed';
27866                    throw new InternalErrorException($msg);
27867                }
27868                break;
27869            case Configure::read('payment_callan_option_join'):
27870                $initialAmount = $amount;
27871                $sendId = isset($ptPaymentParams['sendId']) ? $ptPaymentParams['sendId'] : $userData['id'];
27872                $discounted_amount = isset($ptPaymentParams['discounted_amount']) ? $ptPaymentParams['discounted_amount'] : 0;
27873                $paymentType = Configure::read('payment_types.callan_option');
27874                if ($paymentStatusName == Configure::read('aftee.payment_status_authorised')) {
27875                    $paymentData = array(
27876                        'user_id' => $userData['id'],
27877                        'amount' => $initialAmount,
27878                        'status' => 1,
27879                        'reference_id' => $sendId,
27880                        'payment_transaction_password' => $pt['password'],
27881                        'card_company' => $cardCompany,
27882                        'param1' => json_encode($data),
27883                        'form_type' => $formType,
27884                        'ordd' => $orderCode,
27885                        'transaction_code' => $orderCode,
27886                        'currency_id' => Configure::read('default.settlement_currency_id'), // set currency id to jpy
27887                        'currency_code' => $userData['currency_code'],
27888                        'price_id' => $userData['price_id'],
27889                        'payment_id' => $userData['payment_plan_id'],
27890                        'payment_type' => $paymentType,
27891                        'type_id' => 1,
27892                        'discounted_amount' => $discounted_amount
27893                    );
27894
27895                    // create new payment
27896                    $this->Payment->clear();
27897                    $this->Payment->create();
27898                    $this->Payment->set($paymentData);
27899                    $this->Payment->validate = array();
27900
27901                    // check if payment was not saved
27902                    if (!$this->Payment->save()) {
27903                        $this->log(__METHOD__ . ' Failed to save payment data. ' . json_encode($paymentData) . ' -- ' . json_encode($data), $logFileName);
27904                        $msg = 'Failed to save payment data';
27905                        throw new InternalErrorException($msg);
27906                    }
27907
27908                    // update callan option to 1
27909                    $optionProcessData = array(
27910                        'user_id' => $userData['id'],
27911                        'type' => 'on',
27912                        'option_type' => Configure::read('callan_unlimited.options.callan_unlimited_option')
27913                    );
27914
27915                    $this->User->userNativeOptionProcess($optionProcessData);
27916
27917                    //NJ-2814 add logs
27918                    $optionLogParams = array(
27919                        'user_id' => $userData['id'],
27920                        'platform' => $ncTerminalType,
27921                        'status' => 1, // Join/Subscribed
27922                        'controller_name' => 'Payment',
27923                        'action_name' => 'handleAfteeDirectPaymentSuccess',
27924                        'user_type' => 0, // user
27925                        'option_before' => '',
27926                        'option_after' => 1,
27927                        'option_before_name' => '',
27928                        'option_after_name' => 'Callan Unlimited Option',
27929                        'option_type' => 2,
27930                        'payment_plan_id' => $userData['payment_plan_id']
27931                    );
27932
27933                    ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
27934
27935                    //update/add user`s settlement amount
27936                    $this->User->updateUserPayments($paymentData);
27937
27938                    // update payment transaction
27939                    $updateData = array(
27940                        'id' => $pt['id'],
27941                        'fields' => array(
27942                            'status' => 1,
27943                            'response_text' => array('aftee_directPayment_response' => $data))
27944                    );
27945
27946                    // update payment transaction
27947                    if (!$this->PaymentTransaction->updateAfteePaymentTransaction($updateData)) {
27948                        $this->log(__METHOD__ . ' Failed to update payment transaction' . json_encode($updateData), $logFileName);
27949                        $msg = 'Failed to update payment transaction';
27950                        throw new InternalErrorException($msg);
27951                    }
27952                } else if ($paymentStatusName ==  Configure::read('aftee.payment_status_error')) {
27953                    // aftee payment params
27954                    $afteeParams = array(
27955                        'ptId' => $pt['id'],
27956                        'afteeData' => $data,
27957                        'userId' => $userData['id'],
27958                        'money' => $initialAmount,
27959                        'formType' => $formType,
27960                        'priceId' => $userData['price_id'],
27961                        'paymentId' => $userData['payment_plan_id'],
27962                        'paymentType' => $paymentType,
27963                        'currency' => $userData['currency_code']
27964                    );
27965                    $this->Payment->afteeSaveFailedSettlement($afteeParams);
27966                    $msg = 'Join Callan Option Failed';
27967                    throw new InternalErrorException($msg);
27968                }
27969                break;
27970        }
27971        $response['success'] = true;
27972        return json_encode($response);
27973    }
27974
27975    // NC-7469 Nat Geo ebook send slack email after purchase
27976    public function sendNatGeoEbookPurchaseEmailSlack($data, $user){
27977        $url = myTools::getUrl() . '/admin/user-manage/member/'.$user['id'].'';
27978        $items = "・".implode("\n"."・", $data);
27979        $msg =  "<!subteam^S2PSWAG12|group-cs>" . "\n"; // mention
27980        $msg .= "```";
27981        $msg .= "\n種別: NATIONAL GEOGRAPHIC LEARNING eBook 購入";
27982        $msg .= "\nURL: ".$url."";
27983        $msg .= "\n\n購入内容: \n".$items."";
27984        $msg .= "\n会員ID: ".$user['id']."";
27985        $msg .= "\nニックネーム: ".$user['nickname']."";
27986        $msg .= "\nメールアドレス: ".$user['email']."";
27987        $msg .= "\n\nCS担当者は下記のシートを確認し、会員様にアクセスコードの付与をお願いします。";
27988        $msg .= "\nhttps://www.google.com/url?q=https://docs.google.com/spreadsheets/d/1aZ6ZadwlQcBqXgHjHjwqFMrYuttDWF4TYyyluXSR7_g/edit?usp%3Dsharing&sa=D&ust=1589170738599000&usg=AFQjCNFgZHdilvAmPYj4YnSjUu0v1hyrXA";
27989        $msg .= "```";
27990
27991        $mySlack = new mySlack();
27992        $mySlack->channel = myTools::checkChannel('#nc-nationalgeo-code','#fdc-test-channel');
27993        $mySlack->text = $msg;
27994        $mySlack->username = 'Ebook Purchase';
27995        $mySlack->sendSlack(); //Send slack
27996
27997    }
27998
27999    private function sendEbookPurchaseEmailSlack($data, $user) {
28000        // load Inquiry Model
28001        $this->loadModel("Inquiry");
28002
28003        // NC-7469 National Geo ebook
28004        $natGeoEbook = false;
28005        if ($data['totalNatGeoEbookItems'] > 0) {
28006            $natGeoEbook = true;
28007            $data['templateId'] = Configure::read('site_in_mail.student_purcahse_nat_geo_ebook_complete');
28008            $data['natGeoEbookUrl'] = myTools::getUrl() . '/text_description/national_geographic_ebook';
28009            $data['name'] = $user['nickname'];
28010            $this->sendNatGeoEbookPurchaseEmailSlack($data['items'], $user);
28011        }
28012
28013        // set param
28014        $param = array(
28015            'templateId' => $data['templateId'],
28016            'data' => $data
28017        );
28018
28019        $tempRes = $this->Inquiry->inqTemplate($param);
28020        $message = !empty($tempRes['text']) ? $tempRes['text'] : '';
28021
28022        // send email
28023        $sendMail = myMailer::sendHtmlOrPlainTextEMail(array(
28024            'email_to' => $data['email'],
28025            'email_subject' => !empty($tempRes['title']) ? $tempRes['title'] : '',
28026            'email_body_txt' => $message,
28027            'email_from' => !empty($tempRes['email_from']) ? $tempRes['email_from'] : '',
28028            'native_lang' => !empty($tempRes['native_lang']) ? $tempRes['native_lang'] : '',
28029            'invalid_email_flg' => isset($data['invalid_email_flg']) ? $data['invalid_email_flg'] : 0
28030        ), 'User');
28031
28032        if (!$natGeoEbook) {
28033            $suddenLesson = $this->User->getSuddenLessonCount($data['userId']);
28034            // prepare message
28035            $msg =  "<!subteam^S2PSWAG12|group-cs>" . "\n"; // mention
28036            $msg .= "```";
28037            $msg .= "\n種別:カランeBook購入申請";
28038            $msg .= "\nURL: %url%"; 
28039            $msg .= "\n\n購入内容:"; 
28040            $msg .= "\n%items%"; 
28041            $msg .= "\n\nName: %name%"; 
28042            $msg .= "\nSurname: %lname%";
28043            $msg .= "\nGender: %gender%"; 
28044            $msg .= "\nMember ID: <" . myTools::getUrl() . "/admin/user-manage/member/%userId%|%userId%>"; 
28045            $msg .= "\n通貨 : %currency_code%";
28046            $msg .= "\n言語 : %native_language%";
28047            $msg .= "\n直近30日の今すぐレッスン受講数: %sudden_lesson%回";
28048            $msg .= "```";
28049
28050            $valToReplace = array(
28051                "%url%",
28052                "%items%",
28053                "%name%",
28054                "%lname%",
28055                "%gender%",
28056                "%userId%",
28057                "%currency_code%",
28058                "%native_language%",
28059                "%sudden_lesson%"
28060            );
28061
28062            $replaceValues = array(
28063                isset($data['url']) ? $data['url'] : '',
28064                isset($data['items']) ? "・".implode("\n"."・", $data['items']) : '',
28065                isset($data['name']) ? $data['name'] : '',
28066                isset($data['lastname']) ? $data['lastname'] : '',
28067                isset($data['gender']) ? $data['gender'] : '',
28068                isset($data['userId']) ? $data['userId'] : '',
28069                isset($data['currency_code']) ? $data['currency_code'] : '',
28070                isset($data['native_language']) ? $data['native_language'] : '',
28071                isset($suddenLesson) ? $suddenLesson : '0'
28072            );
28073
28074            $msg = str_replace($valToReplace, $replaceValues ,$msg);
28075
28076            // send to slack
28077            // initialize myslack object
28078            $mySlack = new mySlack();
28079            $mySlack->channel = myTools::checkChannel('#nc-callan-order','#fdc-test-channel');
28080            $mySlack->text = $msg;
28081
28082            // set username
28083            if (!empty($data['slackUsername'])) {
28084                $mySlack->username = $data['slackUsername'];
28085            }
28086
28087            // send to slack
28088            $mySlack->sendSlack();
28089        }
28090
28091        // add memo to user
28092        $memoRes = $this->User->inquiryMemo(
28093            array(
28094                'userId' => $data['userId'],
28095                'data' => array(
28096                    'userId' => $data['userId'],
28097                    'memoTemplate' => $this->User->memoTemplateEbookPurchase,
28098                    'cart' => array(
28099                        'item' => $data['items']
28100                    )
28101                )
28102            )
28103        );
28104
28105        // check if there is error
28106        if (!empty($memoRes['error'])) {
28107        }
28108
28109        $returnVars['error']['is_error'] = false;
28110        return $returnVars; 
28111    }
28112
28113    private function isForTrialReenrollment($userId) {
28114        if ($userId) {    
28115            $reEnroll = $this->UsersDeactivationEnquate->find('first', array(
28116                'fields' => array('membership_type'),
28117                'conditions' => array(
28118                    'UsersDeactivationEnquate.user_id' => $userId,
28119                    'UsersDeactivationEnquate.membership_type' => Configure::read('student_status_type.card_auth')
28120                ),
28121                'order' => 'UsersDeactivationEnquate.created DESC'
28122            ));
28123    
28124            if (!empty($reEnroll)) {
28125                return true;
28126            }
28127        }
28128
28129        return false;
28130    }
28131
28132    /**
28133     * Zeus challenge response
28134     * Kickback from zeus 3d secure 2.0
28135     */
28136    public function checkZeusChallengeResponse(){
28137        $challengeResponse = $this->reportZeusChallengeResponse($this->request->data);
28138        $this->autoRender = $this->autoLayout = false;
28139        $response = $this->request->data;
28140        $response['zeusResponse'] = $challengeResponse;
28141        echo json_encode($response); die();
28142    }
28143
28144
28145    private function setPaymentPlanDetails($user = array(),$paymentPlanID = null ,$logFileName = null){
28146    
28147        if ($user && $paymentPlanID && $logFileName) {
28148                
28149            $currencyCode = $user['currency_code'];
28150            $userId = $user['id'];
28151            $indiCorpTypeLight = false;
28152            $cAmount = 0;
28153            
28154            if ($currencyCode == Configure::read('default.user_currency')) {
28155                // get premium payment plan data
28156                $ppData = $this->PaymentPlanPrice->getPaymentData(array(
28157                    'currencyCode' => $currencyCode,
28158                    'paymentPlanId' => $paymentPlanID,
28159                    'logFileName' => $logFileName
28160                ));
28161
28162                $corporateIndiUser = false;
28163                $corporateUser = isset($user['corporate_id']) && $user['corporate_id'] ? true : false;
28164                $corpType = myTools::getCoporateTypeUsingPaymentPlanId($user['payment_plan_id']);
28165
28166                // - set the default view
28167                $this->set('corporateIndiUser', $corporateIndiUser);
28168                $this->set('corporateType', $corpType);
28169                $this->set('currencyCode', $currencyCode);
28170                $this->set('indiCorpTypeLight', $indiCorpTypeLight);
28171
28172
28173                $cfAmount = "";
28174                $cpAmount = 0;
28175
28176                // if corporate user
28177                if ($corporateUser) {
28178                    // get corporate plan data
28179                    $cpData = $this->getCorporatePaymentPlan($user);
28180
28181                    // return to top page if not supported
28182                    if (!$cpData) {
28183                        return $this->redirect(myTools::getUrl() . '/');
28184                    }
28185
28186                    $cfAmount = $cpData['fAmount'];
28187                    $corporateIndiUser = $cpData['corporateIndiUser'];
28188
28189                }
28190
28191                //NJ-23812: - if corp indie user
28192                if ($corporateIndiUser) {
28193                    $corporateTaxRate = Configure::read('tax.increase');
28194                    
28195                    // light    
28196                    if ($corpType== Configure::read('corporate_type.light')) {
28197                        $indiCorpTypeLight = true;
28198                        $getCorporateData = $this->Corporate->getCorporateLightUserMonthly(array('user_id' => $userId, 'remove_heavy_flg' => true));
28199                        
28200                        $basicFeeWoTax = isset($getCorporateData['basic_fee_discounted']) ? $getCorporateData['basic_fee_discounted'] : 0;
28201                        $cAmount = $basicFeeWoTax;
28202                        $cfAmount = myTools::formatAmount($basicFeeWoTax);
28203
28204                    // standard or premium
28205                    }elseif (in_array($corpType, array(Configure::read('corporate_type.premium'), Configure::read('corporate_type.standard')))) {
28206                        $cdrParam = array('corporateId' => $user['corporate_id'], 'corporateType' => $corpType);
28207                        $discount = (int)$this->CorporateDiscountRate->getDiscount($cdrParam);
28208                        $cAmount = (int)$cpData['amount'] - $discount;
28209                        $cfAmount = myTools::formatAmount($cAmount);
28210                    }
28211                }
28212
28213                // NJ-23812 - set corp user indie
28214                $this->set('corporateIndiUser', $corporateIndiUser);//update 
28215                $this->set('corporateType',$corpType);
28216                $this->set('cpFormatAmount', $cfAmount);
28217                $this->set('cpAmount', $cAmount);
28218                $this->set('ppAmount', $ppData['amount']);
28219                $this->set('ppFormatAmount', $ppData['fAmount']);
28220
28221            }else{
28222
28223                // get premium payment plan data
28224                $ppData = $this->PaymentPlanPrice->getPaymentData(array(
28225                    'currencyCode' => $currencyCode,
28226                    'paymentPlanId' => $paymentPlanID,
28227                    'logFileName' => $logFileName
28228                ));
28229
28230                $currencyData = $this->Currency->getSymbolAndPosition($currencyCode);
28231
28232                $this->set('fAmount', $ppData['fAmount']);
28233                $this->set('ppAmount', $ppData['amount']);
28234
28235                $this->set('monthlyPrice', myTools::customFormatAmount($ppData['amount'], $currencyCode));
28236                $this->set('monthylyPriceNoTax', myTools::formatAmount($ppData['amountConstTaxDeducted']));
28237                $this->set('monthlyPriceSymbol',myTools::getCurrencySymbol($currencyCode));
28238
28239            }  // end if currency code
28240
28241        }
28242    }
28243
28244    private function corpIndividualData($user, $mobapp = array()) {
28245        $corporateIndiUser = false;
28246        $corporateUser = isset($user['corporate_id']) && $user['corporate_id'] ? true : false;
28247
28248        // if corporate user
28249        if ($corporateUser) {
28250            // get corporate plan data
28251            $cpData = $this->getCorporatePaymentPlan($user);
28252
28253            // return to top page if not supported
28254            if (!$cpData) {
28255                return $this->redirect(myTools::getUrl() . '/');
28256            }
28257
28258            $cfAmount = $cpData['fAmount'];
28259            $corporateIndiUser = $cpData['corporateIndiUser'];
28260
28261            $getActivePlans = $this->Corporate->find('first',
28262                [
28263                    'fields' => [
28264                        'cs_display_flg',
28265                        'cp_display_flg',
28266                        'clt_display_flg',
28267                    ],
28268                    'conditions' => [
28269                        'id' => $user['corporate_id']
28270                    ],
28271                    'recursive' => -1
28272                ]
28273            );
28274
28275            $getActivePlansCount = 0;
28276            $getActivePlansCount += $getActivePlans['Corporate']['cs_display_flg'] ? 1 : 0;
28277            $getActivePlansCount += $getActivePlans['Corporate']['cp_display_flg'] ? 1 : 0;
28278            $getActivePlansCount += $getActivePlans['Corporate']['clt_display_flg'] ? 1 : 0;
28279
28280            // default selected plans
28281            $defaultSelectedPlan = 'premium';
28282            if(isset($getActivePlans['Corporate']['cs_display_flg']) && $getActivePlans['Corporate']['cs_display_flg']) {
28283                $defaultSelectedPlan = 'standard';
28284            } else if(isset($getActivePlans['Corporate']['cp_display_flg']) && $getActivePlans['Corporate']['cp_display_flg']){
28285                $defaultSelectedPlan = 'premium';
28286            } else if(isset($getActivePlans['Corporate']['clt_display_flg']) && $getActivePlans['Corporate']['clt_display_flg']){
28287                $defaultSelectedPlan = 'light';
28288            }
28289
28290            $corpActivePlans = array(
28291                'standard'    => $getActivePlans['Corporate']['cs_display_flg'],
28292                'premium'    => $getActivePlans['Corporate']['cp_display_flg'],
28293                'light'        => $getActivePlans['Corporate']['clt_display_flg'],
28294                'count'        => $getActivePlansCount,
28295                'default_selected' => $defaultSelectedPlan
28296            );
28297            $this->set('corpActivePlans',$corpActivePlans);
28298        }
28299
28300        if ($corporateIndiUser) {
28301            $corporateTaxRate = Configure::read('tax.increase');
28302            $corporateIndiPrices = [];
28303
28304            //NJ-28462
28305            // Light Data Prices
28306            $getLightCorporateData = $this->Corporate->getCorporateLightUserMonthly(array(
28307                'user_id' => $user['id'],
28308                'remove_heavy_flg' => true
28309            ));
28310            $paymentLightAmount = isset($getLightCorporateData['total']) ? $getLightCorporateData['total'] : 0;
28311            $basicLightFee = isset($getLightCorporateData['basic_fee']) ? $getLightCorporateData['basic_fee'] : 0;
28312            $lessonLightFee = isset($getLightCorporateData['lesson_fee']) ? $getLightCorporateData['lesson_fee'] : 0;
28313            $basicLightFeeWoTax = isset($getLightCorporateData['basic_fee_discounted']) ? $getLightCorporateData['basic_fee_discounted'] : 0;
28314            $freeLightNumber = isset($getLightCorporateData['fee_charge_count']) ? $getLightCorporateData['fee_charge_count'] : 0;
28315            $isLightFreeFlg = isset($getLightCorporateData['free_charge_flg']) ? $getLightCorporateData['free_charge_flg'] : false;
28316            $monthlyLightFee = isset($getLightCorporateData['monthly_fee_wo_tax']) ? $getLightCorporateData['monthly_fee_wo_tax'] : 0;
28317            $cfLightAmount = myTools::formatAmount($basicLightFeeWoTax);
28318            $cLightRawAmount = $basicLightFeeWoTax;
28319            $lessonLightLimit = $this->Corporate->getLessonLimit($user['corporate_id']);
28320
28321            $CorpLightData = array(
28322                'basicFee' => $basicLightFee,
28323                'lessonFee' => $lessonLightFee,
28324                'freeFlg' => $isLightFreeFlg,
28325                'freeNumber' => $freeLightNumber,
28326                'monthlyFee' => $monthlyLightFee,
28327                'fAmount' => $cfLightAmount,
28328                'paymentAmount' => $paymentLightAmount,
28329                'lessonLimit' => $lessonLightLimit,
28330                'paymentPlanId' => $cpData['paymentPlanId'],
28331                'cRawAmount'    => $cLightRawAmount,
28332                'basicFeeWoTax' => $basicLightFeeWoTax,
28333            );
28334
28335            // Premium Data Prices
28336            $cpPremuimData = $this->getCorporatePaymentPlan($user,array('corporate_type' => 2));
28337            $cdrPremiumParam = array('corporateId' => $user['corporate_id'], 'corporateType' => 2);
28338            $discountPremium = (int)$this->CorporateDiscountRate->getDiscount($cdrPremiumParam);
28339            $cPremiumAmount = (int)$cpPremuimData['amount'] - $discountPremium;
28340            $cPremiumRawAmount = $cPremiumAmount;
28341            $cfPremiumAmount = myTools::formatAmount($cPremiumAmount);
28342            $corpPremiumData = array(
28343                'cprAmount' => $cpPremuimData['amount'],
28344                'cprDiscount' => $discountPremium,
28345                'paymentAmount' => $cPremiumAmount * $corporateTaxRate,
28346                'fAmount' => $cfPremiumAmount,
28347                'cRawAmount' => $cPremiumRawAmount,
28348                'ppAmount' => $cpPremuimData,
28349            );
28350
28351            // Standard Data Prices
28352            $cpStandardData = $this->getCorporatePaymentPlan($user,array('corporate_type' => 1));
28353            $cdrStandardParam = array('corporateId' => $user['corporate_id'], 'corporateType' => 1);
28354            $discountStandard = (int)$this->CorporateDiscountRate->getDiscount($cdrStandardParam);
28355            $cStandardAmount = (int)$cpStandardData['amount'] - $discountStandard;
28356            $cStandardRawAmount = $cStandardAmount;
28357            $cfStandardAmount = myTools::formatAmount($cStandardAmount);
28358            $corpStandardData = array(
28359                'cprAmount' => $cpStandardData['amount'],
28360                'cprDiscount' => $discountStandard,
28361                'paymentAmount' => $cStandardAmount * $corporateTaxRate,
28362                'fAmount' => $cfStandardAmount,
28363                'cRawAmount' => $cStandardRawAmount,
28364                'ppAmount' => $cpStandardData,
28365            );
28366
28367            $corporateIndiPrices['light'] = $CorpLightData;
28368            $corporateIndiPrices['premium'] = $corpPremiumData;
28369            $corporateIndiPrices['standard'] = $corpStandardData;
28370
28371            if(isset($corporateIndiPrices)) {
28372                $this->set('corporateIndiPrices', $corporateIndiPrices);
28373                if(count($mobapp) > 0) {
28374                    $this->memcache->set(array(
28375                        'key' => 'mobappcorporateIndiPrices_'.$mobapp['apiToken'],
28376                        'value' => $corporateIndiPrices,
28377                        'expire' => 3600
28378                    ));
28379                } else {
28380                    $this->Session->write('corporateIndiPrices', $corporateIndiPrices);
28381                }
28382
28383            }
28384
28385            if (isset($corpStandardData)) {
28386                if(count($mobapp) > 0) {
28387                    $this->memcache->set(array(
28388                        'key' => 'mobappCreditChargeCorporateData_'.$user['id'],
28389                        'value' => $corpStandardData,
28390                        'expire' => 3600
28391                    ));
28392                } else {
28393                    $this->Session->write('PaymentCreditChargeCorporateData', $corpStandardData);
28394                }
28395            }
28396        }
28397
28398    }
28399    
28400    /**
28401     * @api {get} /payment/corporate_change_individual_card_payment corporate_change_individual_card_payment()
28402     * @apiName corporate_change_individual_card_payment
28403     * @apiGroup Payment
28404     * @apiDescription This endpoint is used to display the corporate change individual card payment page.
28405     * 
28406     * @apiSuccess {View} Render Displays the corporate change individual card payment page.
28407     * 
28408     * @apiError {View} Redirect Redirects to {{ENV}}/ if the user is not logged in / not a corporate user.
28409     * 
28410     * @apiSuccessExample Success Response:
28411     * Renders the corporate change individual card payment page.
28412     * 
28413     * @apiErrorExample Error Response:
28414     * Redirects to {{ENV}}/
28415     * 
28416     * @apiSampleRequest off
28417     */
28418    public function corporate_change_individual_card_payment() {
28419        if(empty($this->sharedUserData['User'])){
28420            return $this->redirect('/');
28421        }
28422
28423        $userData = $this->sharedUserData['User'];
28424        $userObj = new UserTable($userData);
28425        $fromPage = $this->request->query('from_page');
28426        if (in_array($userObj->getMembershipTypeIndex(), Configure::read('common_corporate_payment_memberships'))) {
28427            return $this->redirect(myTools::getUrl() . '/common_corporate_payment?type='. Configure::read('payment_url_type.corporate_type.corporate_change_individual_card_payment') . '&from_page=' . $fromPage);
28428        }
28429
28430        if(!in_array($userObj->getMembershipTypeIndex(), Configure::read('corp_personal_card_payment_valid_memberships'))){
28431            return $this->redirect('/');
28432        }
28433
28434        $users_detail = $userObj->individualCardFailFlg();
28435        $this->set('individual_card_fail_flg', $users_detail['individual_card_fail_flg'] ?? 0);
28436
28437        $this->getAndSetCardInfo($userData);
28438        $this->set('zeusTransactionFlag', true);
28439        $this->setSupportPayPal($userData);
28440
28441        // - view
28442        $this->render('/Payment/corporate_change_individual_card_payment');
28443    }
28444
28445    public function corp_user_change_personal_card() {
28446        $this->autoRender = $this->autoLayout = false;
28447        $response = ['error' => true, 'msg' => 'Error occured'];
28448
28449        if ($this->request->is('post')) {
28450            $postData = $this->request->data;
28451            $userToken = isset($postData['userApiToken']) ? $postData['userApiToken'] : '';
28452
28453            $userData = [];
28454            if(!empty($this->sharedUserData['User'])){
28455                $userData = $this->sharedUserData['User'];
28456                $this->Session->write('corp_user_change_personal_card', 1);
28457            } elseif ($userToken) {
28458                $userData = $this->User->findByApiToken($userToken);
28459                $userData = $userData['User'];
28460            }
28461
28462            if(!$userData){
28463                $response['msg'] = 'Invalid user';
28464                return json_encode($response);
28465            }
28466
28467            $userObj = new UserTable($userData);
28468            if(!in_array($userObj->getMembershipTypeIndex(), Configure::read('corp_personal_card_payment_valid_memberships'))){
28469                $response['msg'] = 'User is not corporate';
28470                return json_encode($response);
28471            }
28472
28473            //- set user id
28474            $userId = $userObj->id;
28475
28476            //- NJ-42966 - check if user is already paying receivables combine with card registration
28477            $memcache_receivable_data = $this->memcache->get('memcache_receivable_data' . $userId);
28478            $isAleadyPaid = isset($memcache_receivable_data['paying_receivables']) && $memcache_receivable_data['paying_receivables'] == 1;
28479            $isPaymentFailed = isset($memcache_receivable_data['payment_status']) && $memcache_receivable_data['payment_status'] == 1;
28480
28481            // check if 3D secure are already executed
28482            if ($isAleadyPaid) {
28483                $response['error'] = false;
28484                $response['receivable_reservation'] = 1;
28485                $response['payment_status'] = $isPaymentFailed;
28486                $response['paying_receivables'] = $isAleadyPaid;
28487                $response['reserve_response'] = isset($memcache_receivable_data['add_reserve_response']) ? $memcache_receivable_data['add_reserve_response'] : null;
28488                $response['teacher_id'] = isset($memcache_receivable_data['request']['teacherId']) ? $memcache_receivable_data['request']['teacherId'] : 0;
28489                $response['msg'] = 'Already paid';
28490
28491                unset($memcache_receivable_data['paying_receivables']);
28492                unset($memcache_receivable_data['payment_status']);
28493
28494                $this->memcache->set(array(
28495                    'key' => 'memcache_receivable_data' . $userId,
28496                    'value' => $memcache_receivable_data,
28497                    'expire' => 1800 // 30 minutes
28498                ));
28499
28500                return json_encode($response);
28501            }
28502
28503            //- default amount
28504            $paymentAmount = 0;
28505
28506            // get receivable reservation payment
28507            $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userId);
28508            if ($receivablePayment) {
28509                $paymentAmount += $receivablePayment;
28510            }
28511
28512            // get appreciation receivable payments
28513            $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('appreciation_data.payment_element_type'));
28514            if ($appreciationReceivable) {
28515                $paymentAmount += $appreciationReceivable;
28516            }        
28517
28518            // get form information
28519            $data = $postData['ZPaymentFullLogs'];
28520
28521            // set payment params
28522            $paymentParams = array(
28523                'currencyCode' => $userData['currency_code'],
28524                'paymentPlanId' => $userData['payment_plan_id'],
28525                'priceId' => $userData['price_id'],
28526                'remoteAddress' => $_SERVER["REMOTE_ADDR"],
28527                'formType' => Configure::read('corporate_credit_card_registration'),
28528                'paymentType' => Configure::read('payment_types.payment_plan'),
28529                'paymentAmount' => $paymentAmount,
28530                'logFileName' => 'corporate_credit_card_registration',
28531                'corporateSettlementType' => Configure::read('corporate_settlement_types.corporate_card_registration')
28532            );
28533
28534            if (!empty($data['expyy']) && !empty($data['expmm'])) {
28535                $paymentParams['cardExpirationDate'] = date('Y-m-t', strtotime($data['expyy'] . '-' . $data['expmm']));
28536            }
28537
28538            $ptParams = array(
28539                'user_id' => $userId,
28540                'payment_hash' => myTools::generateOrderCode($userId),
28541                'payment_params' => json_encode($paymentParams),
28542                'course_id' => Configure::read("credit.course_id")
28543            );
28544
28545            // redirect to top page if failed to create payment transaction
28546            if (!$pt = $this->PaymentTransaction->setWPPaymentTransaction($ptParams)) {
28547                $response['msg'] = 'Error creating payment transaction';
28548                return json_encode($response);
28549            }
28550
28551            $zeuspayData = array(
28552                'clientIp' => Configure::read('ZEUS_clientip'), # clientip, # clientip
28553                'cardNumber' => isset($data['cardnumber']) ? (int) $data['cardnumber'] : null,
28554                'expyy' => isset($data['expyy']) ? (int) $data['expyy'] : null,
28555                'expmm' => isset($data['expmm']) ? (int) $data['expmm'] : null,
28556                'telNo' => Configure::read('credit.default_telno'), # telephone number
28557                'email' => $userData['email'], # email
28558                'username' => mb_strtoupper($data['username']), # username
28559                'sendId' => $userId, # id
28560                'money' => $paymentAmount, # money
28561                'tokenKey' => $data['zeusTokenValue'],
28562                'paymentHash' => $pt['payment_hash']
28563            );
28564
28565            require_once ROOT.'/user/Controller/Component/ZChargeComponent.php';
28566            // send curl request
28567            $paymentResponse = ZChargeComponent::charge_regist(json_encode($zeuspayData));
28568
28569            if (
28570                (!is_array($paymentResponse) && trim(strtolower($paymentResponse)) == 'success_order') || 
28571                (is_array($paymentResponse) && isset($paymentResponse[0]) && trim(strtolower($paymentResponse[0])) == 'success_order')
28572            ) {
28573
28574                $response['register_card'] = 1;
28575                $purchaseReservationData = '';
28576                $individual_payment_card_empty = false;
28577
28578                //NJ-20741
28579                $memcache_receivable_data = $this->memcache->get('memcache_receivable_data' . $userId);
28580                $reservationCoinPrice = isset($memcache_receivable_data['receivable_reservation_data']['reservation_coin_price']) ? $memcache_receivable_data['receivable_reservation_data']['reservation_coin_price'] : 0;
28581                if ((int)$reservationCoinPrice > 0) {
28582                    $response['teacher_id'] = isset($memcache_receivable_data['request']['teacherId']) ? $memcache_receivable_data['request']['teacherId'] : 0;
28583
28584                    if (isset($memcache_receivable_data['receivable_reservation_data']['reservation_coin_price'])) {
28585                        $memcache_receivable_data['paying_receivables'] = 1;
28586                        $response['receivable_reservation'] = 1;
28587
28588                        $reserveData = isset($memcache_receivable_data['reserve_data']) ? $memcache_receivable_data['reserve_data'] : null;
28589                        if (!empty($reserveData)) {
28590
28591                            $reserveData['paying_receivables'] = 1;
28592                            $reserveData['card_company'] = Configure::read('card_company.zeus');
28593                            if (isset($memcache_receivable_data['actionType']) && $memcache_receivable_data['actionType'] == 'lesson_reservation') {
28594                                try {
28595                                    $reserve_response = $this->LessonSchedule->addReserve($reserveData);
28596                                } catch (\Exception $e) {
28597                                    $this->LessonSchedule->sendSlackExceptionReport([
28598                                        'error_message' => $e->getMessage(),
28599                                        'reserve_data' => $reserveData
28600                                    ]);
28601                                }
28602                            } else if (isset($memcache_receivable_data['actionType']) && $memcache_receivable_data['actionType'] == 'reserved_confirmation') {
28603                                $reserve_response = $this->LessonSchedule->confirmReservationSchedule($reserveData);
28604                            }
28605
28606                            $memcache_receivable_data['reserve_response'] = $reserve_response;
28607
28608                            if (
28609                                isset($reserve_response['lessonSchedId']) && $reserve_response['lessonSchedId'] > 0 &&
28610                                isset($reserve_response['res']) && $reserve_response['res'] == 1
28611                            ) {
28612                                $memcache_receivable_data['add_reserve_response'] = 1;
28613                                $memcache_receivable_data['lessonSchedId'] = $reserve_response['lessonSchedId'];
28614                                $response['reserve_response'] = 1;
28615                            } else if (isset($reserve_response) && $reserve_response == '-1') {
28616                                $memcache_receivable_data['add_reserve_response'] = -1;
28617                                $response['reserve_response'] = -1;
28618                            }
28619
28620                            $individual_payment_card_empty = isset($memcache_receivable_data['receivable_reservation_data']['individual_payment_card_empty']) && $memcache_receivable_data['receivable_reservation_data']['individual_payment_card_empty'] == true;
28621                        }
28622                    }
28623
28624                    if (!empty($memcache_receivable_data)) {
28625                        $this->memcache->set([
28626                            'key' => 'memcache_receivable_data' . $userId,
28627                            'value' => $memcache_receivable_data, 
28628                            'expire' => 1800 // 30 minutes
28629                        ]);
28630                    }
28631                }
28632                // end NJ-20741
28633
28634                //- set success message
28635                $response['error'] = false;
28636                $response['msg'] = 'Successfully register card';
28637            } else {
28638                $response['msg'] = 'Failed to register card';
28639            }
28640
28641            if (!$response['error']) {
28642                $this->memcache->set(array(
28643                    'key' => 'register_or_charge_card_' . $userData['id'],
28644                    'value' => true,
28645                    'expire' => 3600 // 1 hour
28646                ));
28647            }
28648        }
28649
28650        return json_encode($response);
28651    }
28652    /**
28653     * @api {post} /payment/paypal_student_discount_user_change_card/:token paypal_student_discount_user_change_card()
28654     * @apiName paypal_student_discount_user_change_card
28655     * @apiGroup Payment
28656     * @apiDescription This endpoint is used to change the card of a student with a discount.
28657     * 
28658     * @apiParam {String} token User's API token.
28659     * @apiParam {Boolean} [negativeTesting] Negative testing flag.
28660     * 
28661     * @apiSuccess {Boolean} error Indicates if there was an error.
28662     * @apiSuccess {String} msg The message describing the result.
28663     * @apiSuccess {Number} [register_card] Indicates if the card was registered successfully.
28664     * @apiSuccess {Number} [teacher_id] The ID of the teacher.
28665     * @apiSuccess {Number} [receivable_reservation] Indicates if there is a receivable reservation.
28666     * @apiSuccess {Number} [reserve_response] The response for the reservation.
28667     * @apiSuccess {Number} [pay_receivables] Indicates if receivables were paid.
28668     * @apiSuccess {Number} [payment_status] The status of the payment.
28669     * 
28670     * @apiError {Boolean} error Indicates if there was an error.
28671     * @apiError {String} msg The message describing the result.
28672     * 
28673     * @apiSuccessExample Success Response:
28674     * {
28675     *   "error": false,
28676     *   "msg": "Successfully register card",
28677     *   "register_card": 1
28678     * }
28679     * 
28680     * @apiSuccessExample Success Response - Paying Receivables:
28681     * {
28682     *   "error": false,
28683     *   "msg": "Paying receivables",
28684     *   "pay_receivables": 1,
28685     *   "payment_status": 1
28686     * }
28687     * 
28688     * @apiErrorExample Error Response:
28689     * {
28690     *   "error": true,
28691     *   "msg": "Error occurred"
28692     * }
28693     * 
28694     * @apiErrorExample Error Response - Invalid User:
28695     * {
28696     *   "error": true,
28697     *   "msg": "Invalid user"
28698     * }
28699     * 
28700     * @apiErrorExample Error Response - Not Light Plan User:
28701     * {
28702     *   "error": true,
28703     *   "msg": "User is not light plan"
28704     * }
28705     * 
28706     * @apiErrorExample Error Response - Missing Billing Agreement Params:
28707     * {
28708     *   "error": true,
28709     *   "msg": "Missing billing agreement param(s)"
28710     * }
28711     * 
28712     * @apiErrorExample Error Response - Create Order Unsuccessful:
28713     * {
28714     *   "error": true,
28715     *   "msg": "Error creating payment transaction"
28716     * }
28717     * 
28718     * @apiErrorExample Error Response - Authorization Void Unsuccessful:
28719     * {
28720     *   "error": true,
28721     *   "msg": "Error occurred"
28722     * }
28723     * 
28724     * @apiErrorExample Error Response - Failed to Save Settlement History:
28725     * {
28726     *   "error": true,
28727     *   "msg": "Failed to save paypal data in settlement history"
28728     * }
28729     * 
28730     * @apiErrorExample Error Response - Failed to Save Payment Data:
28731     * {
28732     *   "error": true,
28733     *   "msg": "Failed to save payment data"
28734     * }
28735     * 
28736     * @apiErrorExample Error Response - Failed to Update User Data:
28737     * {
28738     *   "error": true,
28739     *   "msg": "Failed to update user data"
28740     * }
28741     * 
28742     * @apiErrorExample Error Response - Error Paying Receivables:
28743     * {
28744     *   "error": true,
28745     *   "msg": "Error Paying receivables"
28746     * }
28747     */
28748    public function paypal_student_discount_user_change_card() {
28749        $this->autoRender = $this->autoLayout = false;
28750        $logFileName = 'discount_option_debug';
28751        $response = ['error' => true, 'msg' => 'Error occured'];
28752        $get = $this->request->query;
28753
28754        // return error if token does is not set
28755        if (!isset($get['token'])) {
28756            $this->log(__METHOD__ . 'User api token does not exist. --> ' . json_encode($get), $logFileName);
28757            return json_encode($response);
28758        }
28759
28760        // negative testing
28761        if (isset($get['negativeTesting']) && $get['negativeTesting']) {
28762            return json_encode($response);
28763        }
28764
28765        if (!class_exists('myMemcached')) {
28766            App::uses('myMemcached', 'Lib');
28767        }
28768
28769        $userToken = $get['token'];
28770        $memcached = new myMemcached();
28771        $memKey = 'paypalBillingAgreementData_' . $userToken;
28772
28773        // return error if memcache billing agreement data does not exist
28774        if (!$paypalData = $memcached->get($memKey)) {
28775            $this->log(__METHOD__ . 'Memcached billing agreement data does not exist. --> ' . json_encode($paypalData) . ' | get data --> ' . json_encode($get), $logFileName);
28776            return json_encode($response);
28777        }
28778
28779        $userData = [];
28780        if (!empty($this->sharedUserData['User'])) {
28781            $userData = $this->sharedUserData['User'];
28782        } elseif ($userToken) {
28783            $userData = $this->User->findByApiToken($userToken);
28784            $userData = $userData['User'];
28785        }
28786
28787        // return error if user does not exist
28788        if (!$userData) {
28789            $response['msg'] = 'Invalid user';
28790            return json_encode($response);
28791        }
28792
28793        $userObj = new UserTable($userData);
28794
28795        // return error if not light plan user
28796        if (!in_array($userObj->getMembershipTypeIndex(), Configure::read('membership_type_lightplan'))){
28797            $response['msg'] = 'User is not light plan';
28798            return json_encode($response);
28799        }
28800
28801        // set payment params
28802        $paymentParams = array(
28803            'currencyCode' => $userData['currency_code'],
28804            'paymentPlanId' => $userData['payment_plan_id'],
28805            'priceId' => $userData['price_id'],
28806            'remoteAddress' => $_SERVER["REMOTE_ADDR"],
28807            'formType' => Configure::read('payment_credit_change'),
28808            'paymentType' => Configure::read('payment_types.payment_plan'),
28809            'paymentAmount' => 0,
28810            'logFileName' => $logFileName
28811        );
28812
28813        // initialize variables
28814        $userId = $userObj->id;
28815        $currencyCode = $userObj->currency_code;
28816        $paymentPlanId = $userObj->payment_plan_id;
28817        $priceId = $userObj->price_id;
28818        $paymentHash = myTools::generateOrderCode($userId);
28819        $ptParams = array(
28820            'user_id' => $userId,
28821            'payment_hash' => $paymentHash,
28822            'payment_params' => json_encode($paymentParams),
28823            'course_id' => Configure::read("credit.course_id")
28824        );
28825
28826        // return error if failed to create payment transaction
28827        if (!$pt = $this->PaymentTransaction->setWPPaymentTransaction($ptParams)) {
28828            $response['msg'] = 'Error creating payment transaction';
28829            return json_encode($response);
28830        }
28831
28832        $ptId = $pt['id'];
28833
28834        // return error if missing billing agreement params
28835        if (
28836            !isset($paypalData['accessTokenData']['access_token']) || 
28837            !isset($paypalData['finalizeBillingAgreementData']['id']) ||
28838            !isset($paypalData['finalizeBillingAgreementData']['payer']['payer_info']['payer_id'])
28839        ) {
28840            $this->log(__METHOD__ . 'Missing billing agreement param(s). --> ' . json_encode($paypalData), $logFileName);
28841
28842            // update payment transaction
28843            $this->PaymentTransaction->paypalUpdatePaymentTransaction(array('ptId' => $ptId, 'paypalData' => $paypalData));
28844
28845            return json_encode($response);
28846        }
28847
28848        $accessToken = $paypalData['accessTokenData']['access_token'];
28849        $baId = $paypalData['finalizeBillingAgreementData']['id']; // billing agreement id
28850        $payerId = $paypalData['finalizeBillingAgreementData']['payer']['payer_info']['payer_id'];
28851
28852        // load PayPal class
28853        if (!class_exists('PayPal')) {
28854            App::import('Lib', 'PayPal');
28855        }
28856
28857        $paypal = new PayPal();
28858        $createOrderParams = array(
28859            'accessToken' => $accessToken,
28860            'paypalRequestId' => $ptId,
28861            'intent' => 'AUTHORIZE',
28862            'paymentHash' => $paymentHash,
28863            'userId' => $userId,
28864            'currencyCode' => $currencyCode,
28865            'amount' => 1,
28866            'billingAgreementId' => $baId
28867        );
28868
28869        // create order
28870        $orderResult = $paypal->createOrder($createOrderParams);
28871
28872        $paypalData['create_order_data'] = $orderResult;
28873
28874        // return error if create order unsuccessful
28875        if (!isset($orderResult['status']) || (isset($orderResult['status']) && $orderResult['status'] !== 'COMPLETED')) {
28876            $this->log(__METHOD__ . 'Create order error. --> ' . json_encode($orderResult) . ' | params --> ' . json_encode($createOrderParams) . ' | paypal data --> ' . json_encode($paypalData), $logFileName);
28877
28878            // update payment transaction
28879            $this->PaymentTransaction->paypalUpdatePaymentTransaction(array('ptId' => $ptId, 'paypalData' => $paypalData));
28880
28881            return json_encode($response);
28882        }
28883
28884        $authorizationVoidParams = array(
28885            'accessToken' => $accessToken,
28886            'authorizationId' => $orderResult['purchase_units'][0]['payments']['authorizations'][0]['id']
28887        );
28888
28889        // void authorization
28890        // expected return empty if success
28891        $voidResult = $paypal->authorizationVoid($authorizationVoidParams);
28892
28893        $paypalData['authorization_void_data'] = $voidResult; // expected empty
28894
28895        // return error if paypal transaction unsuccessful
28896        if (!empty($voidResult)) {
28897            $this->log(__METHOD__ . ' authorization void error. --> ' . json_encode($voidResult) . ' | params --> ' . json_encode($authorizationVoidParams) . ' | paypal data --> ' . json_encode($paypalData), $logFileName);
28898
28899            // update payment transaction
28900            $this->PaymentTransaction->paypalUpdatePaymentTransaction(array('ptId' => $ptId, 'paypalData' => $paypalData));
28901
28902            return json_encode($response);
28903        }
28904
28905        // save settlement history for tracking
28906        if (!SettlementHistoryTable::add(
28907            array(
28908                'userId' => $userId,
28909                'params' => json_encode($paypalData)
28910            )
28911        )) {
28912            $this->log(__METHOD__ . 'Failed to save paypal data in settlement history. --> ' . json_encode($orderResult) . ' | params --> ' . json_encode($createOrderParams) . ' | paypal data --> ' . json_encode($paypalData), $logFileName);
28913
28914            // update payment transaction
28915            $this->PaymentTransaction->paypalUpdatePaymentTransaction(array('ptId' => $ptId, 'paypalData' => $paypalData));
28916
28917            return json_encode($response);
28918        }
28919
28920        $cardCompany = Configure::read('card_company.paypal');
28921
28922        $savePaymentArr = array(
28923            'user_id' => $userId,
28924            'amount' => 0,
28925            'status' => 1,
28926            'reference_id' => $userId,
28927            'payment_transaction_password' => $pt['password'],
28928            'card_company' => $cardCompany,
28929            'param1' => "paypal change card, payment transaction id: {$ptId}",
28930            'form_type' => Configure::read('payment_credit_change'),
28931            'ordd' => $paymentHash,
28932            'transaction_code' => $paymentHash,
28933            'currency_id' => Configure::read('default.settlement_currency_id'), // set currency id to jpy
28934            'currency_code' => $currencyCode,
28935            'payment_id' => $paymentPlanId,
28936            'price_id' => $priceId,
28937            'payment_type' => Configure::read('payment_types.payment_plan')
28938        );
28939
28940        // create new payment
28941        $this->Payment->clear();
28942        $this->Payment->create();
28943        $this->Payment->set($savePaymentArr);
28944        if (!$this->Payment->save()) {
28945            $this->log(__METHOD__ . ' Failed to save payment data. --> ' . json_encode($savePaymentArr) . ' | paypal data --> ' . json_encode($paypalData), $logFileName);
28946            $dataSource->rollback();
28947
28948            // update payment transaction
28949            $this->PaymentTransaction->paypalUpdatePaymentTransaction(array('ptId' => $ptId, 'paypalData' => $paypalData));
28950
28951            return json_encode($response);
28952        }
28953
28954        $dateNow = date('Y-m-d H:i:s');
28955        $saveUserArr = array(
28956            'status' => 1,
28957            'modified' => $dateNow,
28958            'fail_flg' => 0,
28959            'charge_flg' => 1,
28960            'counseling_attended_flg' => 0,
28961            'card_company' => $cardCompany,
28962            'hash16' => $userId,
28963            'last_charge_date' => $dateNow,
28964            'paypal_billing_agreement_id' => $baId,
28965            'paypal_payer_id' => $payerId,
28966            'card_expiration_date' => null
28967        );
28968
28969        $this->User->read(array_keys($saveUserArr), $userId);
28970        $this->User->set($saveUserArr);
28971        $this->User->validate = array();
28972        if (!$this->User->save()) {
28973            $this->log(__METHOD__ . ' Failed to update user data. --> ' . json_encode($saveUserArr) . ' | user id --> ' . $userId . ' | paypal data --> ' . json_encode($paypalData), $logFileName);
28974            return json_encode($response);
28975        }
28976
28977        $response['register_card'] = 1;
28978        $purchaseReservationData = '';
28979        $individual_payment_card_empty = false;
28980        $memcache_receivable_data = $this->memcache->get('memcache_receivable_data' . $userId);
28981        $reservationCoinPrice = isset($memcache_receivable_data['receivable_reservation_data']['reservation_coin_price']) ? $memcache_receivable_data['receivable_reservation_data']['reservation_coin_price'] : 0;
28982        if ((int)$reservationCoinPrice > 0) {
28983            $response['teacher_id'] = isset($memcache_receivable_data['request']['teacherId']) ? $memcache_receivable_data['request']['teacherId'] : 0;
28984
28985            if (isset($memcache_receivable_data['receivable_reservation_data']['reservation_coin_price'])) {
28986                $memcache_receivable_data['paying_receivables'] = 1;
28987                $response['receivable_reservation'] = 1;
28988
28989                $reserveData = isset($memcache_receivable_data['reserve_data']) ? $memcache_receivable_data['reserve_data'] : null;
28990                if (!empty($reserveData)) {
28991
28992                    $reserveData['paying_receivables'] = 1;
28993                    $reserveData['card_company'] = Configure::read('card_company.zeus');
28994                    if (isset($memcache_receivable_data['actionType']) && $memcache_receivable_data['actionType'] == 'lesson_reservation') {
28995                        try {
28996                            $reserve_response = $this->LessonSchedule->addReserve($reserveData);
28997                        } catch (\Exception $e) {
28998                            $this->LessonSchedule->sendSlackExceptionReport([
28999                                'error_message' => $e->getMessage(),
29000                                'reserve_data' => $reserveData
29001                            ]);
29002                        }
29003                    } else if (isset($memcache_receivable_data['actionType']) && $memcache_receivable_data['actionType'] == 'reserved_confirmation') {
29004                        $reserve_response = $this->LessonSchedule->confirmReservationSchedule($reserveData);
29005                    }
29006
29007                    $memcache_receivable_data['reserve_response'] = $reserve_response;
29008
29009                    if (
29010                        isset($reserve_response['lessonSchedId']) && $reserve_response['lessonSchedId'] > 0 &&
29011                        isset($reserve_response['res']) && $reserve_response['res'] == 1
29012                    ) {
29013                        $memcache_receivable_data['add_reserve_response'] = 1;
29014                        $memcache_receivable_data['lessonSchedId'] = $reserve_response['lessonSchedId'];
29015                        $response['reserve_response'] = 1;
29016                    } else if (isset($reserve_response) && $reserve_response == '-1') {
29017                        $memcache_receivable_data['add_reserve_response'] = -1;
29018                        $response['reserve_response'] = -1;
29019                    }
29020
29021                    $individual_payment_card_empty = isset($memcache_receivable_data['receivable_reservation_data']['individual_payment_card_empty']) && $memcache_receivable_data['receivable_reservation_data']['individual_payment_card_empty'] == true;
29022                }
29023            }
29024
29025            if (!empty($memcache_receivable_data)) {
29026                $this->memcache->set([
29027                    'key' => 'memcache_receivable_data' . $userId,
29028                    'value' => $memcache_receivable_data, 
29029                    'expire' => 1800 // 30 minutes
29030                ]);
29031            }
29032        }
29033
29034        $paymentAmount = 0;
29035
29036        // get receivable reservation payment
29037        $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userId);
29038        if ($receivablePayment) {
29039            $paymentAmount += $receivablePayment;
29040        }
29041
29042        // - pay receivables
29043        if ($paymentAmount && $individual_payment_card_empty == false) {
29044            $response['pay_receivables'] = 1;
29045
29046            // - payment transaction params
29047            $paymentHash = myTools::generateOrderCode($userId);
29048            $receivablePT = array(
29049                'userId' => $userId,
29050                'status' => 0,
29051                'paymentHash' => $paymentHash,
29052                'paymentParams' => json_encode(array(
29053                    'currencyCode' => $currencyCode,
29054                    'formType' => Configure::read('payment_credit_receivable'),
29055                    'paymentType' => Configure::read('payment_types.payment_receivable'),
29056                    'paymentAmount' => $paymentAmount,
29057                    'paymentPlanId' => $paymentPlanId,
29058                    'priceId' => $priceId
29059                )),
29060                'responseText' => '',
29061                'logFileName' => ''
29062            );
29063
29064            if (!$pt = $this->PaymentTransaction->setWPPaymentTransaction($ptParams)) {
29065                $response['error'] = true;
29066                $response['msg'] = 'Error creating payment trasaction for receivable payments';
29067                return json_encode($response);
29068            }
29069
29070            $ptId = $pt['id'];
29071
29072            // settle receivable
29073            $createOrderParams = array(
29074                'accessToken' => $accessToken,
29075                'paypalRequestId' => $ptId,
29076                'intent' => 'CAPTURE',
29077                'paymentHash' => $paymentHash,
29078                'userId' => $userId,
29079                'currencyCode' => $currencyCode,
29080                'amount' => (int)$paymentAmount,
29081                'billingAgreementId' => $baId
29082            );
29083
29084            // create order
29085            $createOrderResult = $paypal->createOrder($createOrderParams);
29086            $paypalData['create_order_data'] = $createOrderResult;
29087
29088            // save settlement history for tracking
29089            if (
29090                !SettlementHistoryTable::add(array(
29091                    'userId' => $userId,
29092                    'params' => json_encode($paypalData),
29093                    'createdIp' => $dateNow,
29094                    'modifiedIp' => $dateNow
29095                )
29096            )) {
29097                $this->log(__METHOD__ . ' Failed to save paypal result data in settlement history. ' . json_encode($paypalData), $logFileName);
29098                return json_encode($response);
29099            }
29100
29101            if (isset($createOrderResult['status']) && $createOrderResult['status'] === 'COMPLETED') {
29102                $paymentData = array(
29103                    'user_id' => $userId,
29104                    'amount' => $paymentAmount,
29105                    'status' => 1,
29106                    'reference_id' => $userId,
29107                    'payment_transaction_password' => $pt['password'],
29108                    'card_company' => $cardCompany,
29109                    'param1' => json_encode($paypalData),
29110                    'form_type' => Configure::read('payment_credit_receivable'),
29111                    'ordd' => $paymentHash,
29112                    'transaction_code' => $paymentHash,
29113                    'currency_id' => Configure::read('default.settlement_currency_id'),
29114                    'currency_code' => $currencyCode,
29115                    'payment_id' => $paymentPlanId,
29116                    'price_id' => $priceId,
29117                    'payment_type' => Configure::read('payment_types.payment_plan')
29118                );
29119    
29120                // create new payment
29121                $this->Payment->clear();
29122                $this->Payment->create();
29123                $this->Payment->set($paymentData);
29124                $this->Payment->validate = array();
29125    
29126                // check if payment was not saved
29127                if (!$this->Payment->save()) {
29128                    $this->log(__METHOD__ . ' Failed to save payment data. ' . json_encode($paymentData) . ' -- ' . json_encode($data), $logFileName);
29129                    return json_encode($response);
29130                }
29131    
29132                $paymentId = $this->Payment->id;
29133                //update/add user`s settlement amount
29134                $this->User->updateUserPayments($paymentData);
29135
29136                // set payment_id
29137                $paymentId = $this->Payment->id;
29138                $membershipStatusIndex = UserTable::getStudentMembershipStatus($userId);
29139
29140                // set payment receivable statuses to 2 - received
29141                $this->PaymentReceivable->updateReceivableReservationPayment(
29142                    $userId,
29143                    array(
29144                        'status' => 2,
29145                        'payment_id' => $paymentId,
29146                        'payment_collection_date' => date("Y-m-d H:i:s"),
29147                        'card_company' => $cardCompany,
29148                        'payment_plan_id' => $paymentPlanId,
29149                        'membership_type_index' => $membershipStatusIndex
29150                    ),
29151                    array(
29152                        'PaymentReceivable.user_id' => $userId,
29153                        'PaymentReceivable.status' => 0,
29154                        'PaymentReceivable.payment_element_type' => 1,
29155                        'PaymentReceivable.created <=' => date("Y-m-d H:i:s")
29156                    )
29157                );
29158
29159                $response['payment_status'] = 1;
29160                $response['error'] = false;
29161                $response['msg'] = 'Paying receivables';
29162            } else {
29163                $response['msg'] = 'Error Paying receivables';
29164            }
29165        } else {
29166            $response['error'] = false;
29167            $response['msg'] = 'Successfully register card';
29168        }
29169
29170        if (!$response['error']) {
29171            $this->memcache->set(array(
29172                'key' => 'register_or_charge_card_' . $userData['id'],
29173                'value' => true,
29174                'expire' => 3600 // 1 hour
29175            ));
29176        }
29177
29178        return json_encode($response);
29179    }
29180    /**
29181     * @api {post} /payment/student_discount_user_change_card/:token student_discount_user_change_card()
29182     * @apiName student_discount_user_change_card
29183     * @apiGroup Payment
29184     * @apiDescription This endpoint is used to change the card of a student with a discount.
29185     * 
29186     * @apiParam {String} token User's API token.
29187     * @apiParam {Boolean} [negativeTesting] Negative testing flag.
29188     * 
29189     * @apiSuccess {Boolean} error Indicates if there was an error.
29190     * @apiSuccess {String} msg The message describing the result.
29191     * @apiSuccess {Number} [register_card] Indicates if the card was registered successfully.
29192     * @apiSuccess {Number} [teacher_id] The ID of the teacher.
29193     * @apiSuccess {Number} [receivable_reservation] Indicates if there is a receivable reservation.
29194     * @apiSuccess {Number} [reserve_response] The response for the reservation.
29195     * @apiSuccess {Number} [pay_receivables] Indicates if receivables were paid.
29196     * @apiSuccess {Number} [payment_status] The status of the payment.
29197     * 
29198     * @apiError {Boolean} error Indicates if there was an error.
29199     * @apiError {String} msg The message describing the result.
29200     * 
29201     * @apiSuccessExample Success Response:
29202     * {
29203     *   "error": false,
29204     *   "msg": "Successfully register card",
29205     *   "register_card": 1
29206     * }
29207     * 
29208     * @apiSuccessExample Success Response - Paying Receivables:
29209     * {
29210     *   "error": false,
29211     *   "msg": "Paying receivables",
29212     *   "pay_receivables": 1,
29213     *   "payment_status": 1
29214     * }
29215     * 
29216     * @apiErrorExample Error Response:
29217     * {
29218     *   "error": true,
29219     *   "msg": "Error occurred"
29220     * }
29221     * 
29222     * @apiErrorExample Error Response - Invalid User:
29223     * {
29224     *   "error": true,
29225     *   "msg": "Invalid user"
29226     * }
29227     * 
29228     * @apiErrorExample Error Response - Not Light Plan User:
29229     * {
29230     *   "error": true,
29231     *   "msg": "User is not light plan"
29232     * }
29233     * 
29234     * @apiErrorExample Error Response - Failed to Register Card:
29235     * {
29236     *   "error": true,
29237     *   "msg": "Failed to register card"
29238     * }
29239     * 
29240     * @apiErrorExample Error Response - Error Creating Payment Transaction:
29241     * {
29242     *   "error": true,
29243     *   "msg": "Error creating payment transaction"
29244     * }
29245     *     
29246     * @apiErrorExample Error Response - Error Paying Receivables:
29247     * {
29248     *   "error": true,
29249     *   "msg": "Error Paying receivables"
29250     * }
29251     */
29252    public function student_discount_user_change_card() {
29253        $this->autoRender = $this->autoLayout = false;
29254        $response = ['error' => true, 'msg' => 'Error occured'];
29255
29256        if ($this->request->is('post')) {
29257            $postData = $this->request->data;
29258            $userToken = isset($postData['userApiToken']) ? $postData['userApiToken'] : '';
29259
29260            $userData = [];
29261            if (!empty($this->sharedUserData['User'])) {
29262                $userData = $this->sharedUserData['User'];
29263            } elseif ($userToken) {
29264                $userData = $this->User->findByApiToken($userToken);
29265                $userData = $userData['User'];
29266            }
29267
29268            if (!$userData) {
29269                $response['msg'] = 'Invalid user';
29270                return json_encode($response);
29271            }
29272
29273            $userObj = new UserTable($userData);
29274            if (!in_array($userObj->getMembershipTypeIndex(), Configure::read('membership_type_lightplan'))){
29275                $response['msg'] = 'User is not light plan';
29276                return json_encode($response);
29277            }
29278
29279            // get form information
29280            $data = $postData['ZPaymentFullLogs'];
29281
29282            // set payment params
29283            $paymentParams = array(
29284                'currencyCode' => $userData['currency_code'],
29285                'paymentPlanId' => $userData['payment_plan_id'],
29286                'priceId' => $userData['price_id'],
29287                'remoteAddress' => $_SERVER["REMOTE_ADDR"],
29288                'formType' => Configure::read('payment_credit_change'),
29289                'paymentType' => Configure::read('payment_types.payment_plan'),
29290                'paymentAmount' => 0,
29291                'logFileName' => 'discount_option_debug'
29292            );
29293
29294            if (!empty($data['expyy']) && !empty($data['expmm'])) {
29295                $paymentParams['cardExpirationDate'] = date('Y-m-t', strtotime($data['expyy'] . '-' . $data['expmm']));
29296            }
29297
29298            $userId = $userData['id'];
29299            $ptParams = array(
29300                'user_id' => $userId,
29301                'payment_hash' => myTools::generateOrderCode($userId),
29302                'payment_params' => json_encode($paymentParams),
29303                'course_id' => Configure::read("credit.course_id")
29304            );
29305
29306            // redirect to top page if failed to create payment transaction
29307            if (!$pt = $this->PaymentTransaction->setWPPaymentTransaction($ptParams)) {
29308                $response['msg'] = 'Error creating payment transaction';
29309                return json_encode($response);
29310            }
29311
29312            $zeuspayData = array(
29313                'clientIp' => Configure::read('ZEUS_clientip'), # clientip, # clientip
29314                'cardNumber' => isset($data['cardnumber']) ? (int) $data['cardnumber'] : null,
29315                'expyy' => isset($data['expyy']) ? (int) $data['expyy'] : null,
29316                'expmm' => isset($data['expmm']) ? (int) $data['expmm'] : null,
29317                'telNo' => Configure::read('credit.default_telno'), # telephone number
29318                'email' => $userData['email'], # email
29319                'username' => mb_strtoupper($data['username']), # username
29320                'sendId' => $userId, # id
29321                'money' => 0, # money
29322                'tokenKey' => $data['zeusTokenValue'],
29323                'paymentHash' => $pt['payment_hash']
29324            );
29325
29326            //NJ-20741
29327            $memcache_receivable_data = $this->memcache->get('memcache_receivable_data' . $userId);
29328            $isAleadyPaid = isset($memcache_receivable_data['paying_receivables']) && $memcache_receivable_data['paying_receivables'] == 1;
29329            $isPaymentFailed = isset($memcache_receivable_data['payment_status']) && $memcache_receivable_data['payment_status'] == 1;
29330            
29331            // check if 3D secure are already executed
29332            if ($isAleadyPaid) {
29333                $response['error'] = false;
29334                $response['receivable_reservation'] = 1;
29335                $response['payment_status'] = $isPaymentFailed;
29336                $response['paying_receivables'] = $isAleadyPaid;
29337                $response['reserve_response'] = isset($memcache_receivable_data['add_reserve_response']) ? $memcache_receivable_data['add_reserve_response'] : null;
29338                $response['teacher_id'] = isset($memcache_receivable_data['request']['teacherId']) ? $memcache_receivable_data['request']['teacherId'] : 0;
29339                $response['msg'] = 'Already paid';
29340
29341                unset($memcache_receivable_data['paying_receivables']);
29342                unset($memcache_receivable_data['payment_status']);
29343
29344                $this->memcache->set(array(
29345                    'key' => 'memcache_receivable_data' . $userId,
29346                    'value' => $memcache_receivable_data,
29347                    'expire' => 1800 // 30 minutes
29348                ));
29349
29350                return json_encode($response);
29351            }
29352
29353            require_once ROOT.'/user/Controller/Component/ZChargeComponent.php';
29354            // send curl request
29355            $paymentResponse = ZChargeComponent::charge_regist(json_encode($zeuspayData));
29356
29357            if (
29358                (!is_array($paymentResponse) && trim(strtolower($paymentResponse)) == 'success_order') || 
29359                (is_array($paymentResponse) && isset($paymentResponse[0]) && trim(strtolower($paymentResponse[0])) == 'success_order')
29360            ) {
29361
29362                $response['register_card'] = 1;
29363                $purchaseReservationData = '';
29364                $individual_payment_card_empty = false;
29365
29366                //NJ-20741
29367                $memcache_receivable_data = $this->memcache->get('memcache_receivable_data' . $userId);
29368                $reservationCoinPrice = isset($memcache_receivable_data['receivable_reservation_data']['reservation_coin_price']) ? $memcache_receivable_data['receivable_reservation_data']['reservation_coin_price'] : 0;
29369                if ((int)$reservationCoinPrice > 0) {
29370                    $response['teacher_id'] = isset($memcache_receivable_data['request']['teacherId']) ? $memcache_receivable_data['request']['teacherId'] : 0;
29371
29372                    if (isset($memcache_receivable_data['receivable_reservation_data']['reservation_coin_price'])) {
29373                        $memcache_receivable_data['paying_receivables'] = 1;
29374                        $response['receivable_reservation'] = 1;
29375
29376                        $reserveData = isset($memcache_receivable_data['reserve_data']) ? $memcache_receivable_data['reserve_data'] : null;
29377                        if (!empty($reserveData)) {
29378
29379                            $reserveData['paying_receivables'] = 1;
29380                            $reserveData['card_company'] = Configure::read('card_company.zeus');
29381                            if (isset($memcache_receivable_data['actionType']) && $memcache_receivable_data['actionType'] == 'lesson_reservation') {
29382                                try {
29383                                    $reserve_response = $this->LessonSchedule->addReserve($reserveData);
29384                                } catch (\Exception $e) {
29385                                    $this->LessonSchedule->sendSlackExceptionReport([
29386                                        'error_message' => $e->getMessage(),
29387                                        'reserve_data' => $reserveData
29388                                    ]);
29389                                }
29390                            } else if (isset($memcache_receivable_data['actionType']) && $memcache_receivable_data['actionType'] == 'reserved_confirmation') {
29391                                $reserve_response = $this->LessonSchedule->confirmReservationSchedule($reserveData);
29392                            }
29393
29394                            $memcache_receivable_data['reserve_response'] = $reserve_response;
29395
29396                            if (
29397                                isset($reserve_response['lessonSchedId']) && $reserve_response['lessonSchedId'] > 0 &&
29398                                isset($reserve_response['res']) && $reserve_response['res'] == 1
29399                            ) {
29400                                $memcache_receivable_data['add_reserve_response'] = 1;
29401                                $memcache_receivable_data['lessonSchedId'] = $reserve_response['lessonSchedId'];
29402                                $response['reserve_response'] = 1;
29403                            } else {
29404                                $memcache_receivable_data['add_reserve_response'] = -1;
29405                                $response['reserve_response'] = -1;
29406                            }
29407
29408                            $individual_payment_card_empty = isset($memcache_receivable_data['receivable_reservation_data']['individual_payment_card_empty']) && $memcache_receivable_data['receivable_reservation_data']['individual_payment_card_empty'] == true;
29409                        }
29410                    }
29411
29412                    if (!empty($memcache_receivable_data)) {
29413                        $this->memcache->set([
29414                            'key' => 'memcache_receivable_data' . $userId,
29415                            'value' => $memcache_receivable_data, 
29416                            'expire' => 1800 // 30 minutes
29417                        ]);
29418                    }
29419                }
29420                // end NJ-20741
29421
29422                $paymentAmount = 0;
29423
29424                // get receivable reservation payment
29425                $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userId);
29426                if ($receivablePayment) {
29427                    $paymentAmount += $receivablePayment;
29428                }
29429
29430                // get appreciation receivable payments
29431                $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('appreciation_data.payment_element_type'));
29432                if ($appreciationReceivable) {
29433                    $paymentAmount += $appreciationReceivable;
29434                }
29435
29436                // - pay receivables
29437                if($paymentAmount && $individual_payment_card_empty == false){
29438                    $response['pay_receivables'] = 1;
29439                    // - payment transaction params
29440                    $paymentHash = myTools::generateOrderCode($userId);
29441                    $receivablePT = array(
29442                        'userId' => $userId,
29443                        'status' => 0,
29444                        'paymentHash' => $paymentHash,
29445                        'paymentParams' => json_encode(array(
29446                            'currencyCode' => $userData['currency_code'],
29447                            'formType' => Configure::read('payment_credit_receivable'),
29448                            'paymentType' => Configure::read('payment_types.payment_receivable'),
29449                            'paymentAmount' => $paymentAmount,
29450                            'paymentPlanId' => $userData['payment_plan_id'],
29451                            'priceId' => $userData['price_id']
29452                        )),
29453                        'responseText' => '',
29454                        'logFileName' => ''
29455                    );
29456
29457                    // - creating payment transaction
29458                    if (!$this->PaymentTransaction->rawSaveCronPaymentTransaction($receivablePT)) {
29459                        $response['error'] = true;
29460                        $response['msg'] = 'Error creating payment trasaction for receivable payments';
29461                        return json_encode($response);
29462                    }
29463
29464                    $zp_receivable_params = array(
29465                        'clientIp' => Configure::read('ZEUS_clientip'),
29466                        'email' => $userData['email'],
29467                        'sendId' => $userId,
29468                        'money' => $paymentAmount,
29469                        'paymentHash' => $paymentHash
29470                    );
29471    
29472                    $receivable_response = ZChargeComponent::charge_with_regsterd_card(json_encode($zp_receivable_params));
29473
29474                    // check if successful 
29475                    if ($receivable_response === "Success_order") {
29476                        $response['payment_status'] = 1;
29477                        $response['error'] = false;
29478                        $response['msg'] = 'Paying receivables';
29479                    } else {
29480                        $response['msg'] = 'Error Paying receivables';
29481                    }
29482
29483
29484                } else {
29485                    $response['error'] = false;
29486                    $response['msg'] = 'Successfully register card';
29487                }
29488                
29489            } else {
29490                $response['msg'] = 'Failed to register card';
29491            }
29492
29493            if(!$response['error']){
29494                $this->memcache->set(array(
29495                    'key' => 'register_or_charge_card_' . $userData['id'],
29496                    'value' => true,
29497                    'expire' => 3600 // 1 hour
29498                ));
29499            }
29500        }
29501
29502        return json_encode($response);
29503    }
29504    /**
29505     * @api {get} /mobapp/payment/corporate_user_change_personal_card_payment/:token/:cardToken mobapp_corporate_change_individual_card_payment()
29506     * @apiName mobapp_corporate_change_individual_card_payment
29507     * @apiGroup Payment
29508     * @apiDescription Change individual card payment for corporate user
29509     * 
29510     * @apiParam {String} token User token
29511     * @apiParam {String} cardToken Card token. Blank if not provided
29512     *  
29513     * @apiBody {Object[]} ZPaymentFullLogs The payment details.
29514     * @apiBody {Number} ZPaymentFullLogs.cardnumber The credit card number.
29515     * @apiBody {Number} ZPaymentFullLogs.expyy The expiration year of the credit card.
29516     * @apiBody {Number} ZPaymentFullLogs.expmm The expiration month of the credit card.
29517     * @apiBody {String} ZPaymentFullLogs.username The name on the credit card.
29518     * @apiBody {String} ZPaymentFullLogs.zeusTokenValue The token value for the credit card.
29519     * @apiBody {Number} ZPaymentFullLogs.payment_plan_type The payment plan type.
29520     * @apiBody {String} ZPaymentFullLogs.paymentHash The payment hash.
29521     * @apiBody {Number} ZPaymentFullLogs.money The payment amount.
29522     * @apiBody {Number} ZPaymentFullLogs.formType The form type. Is set to 2.
29523     * @apiBody {Number} ZPaymentFullLogs.retainIndiPlan The retain individual plan flag.\
29524     * @apiBody {String} ZPaymentFullLogs.telno The telephone number.
29525     * @apiBOdy {String} ZPaymentFulllogs.clientip The client IP address.
29526     * @apiBody {String} ZPaymentFullLogs.corporatePlan The corporate plan.
29527     * @apiBody {String} ZPaymentFullLogs.indiCorpType The individual corporate type. 4 for individual plan.
29528     * @apiBody {String} token The user token.
29529     * @apiBody {String} cardToken The card token.
29530     * @apiBody {Number} payment_gateway_type The payment gateway type. Default is 1 for zeus. 6 for paypal.
29531     * @apiBody {Object[]} [paymentPlanData] The payment plan data for paypal gateway.
29532     * @apiBody {String} [paymentPlanData.amount] The payment amount.
29533     * @apiBody {String} [paymentPlanData.priceId] The price ID.
29534     * @apiBody {String} [paymentPlanData.paymentPlanId] The payment plan ID.
29535     * @apiBody {Number} receivablePayment The receivable payment amount
29536     * @apiBody {Number} appreciationReceivable The appreciation receivable payment amount
29537     * @apiBody {Number} liveLessonReceivable The live lesson receivable payment amount
29538     * 
29539     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/mobapp_credit_charge_confirm for successful credit charge. 
29540     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/paypal_payment_credit_charge_confirm for paypal success
29541     * 
29542     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage for failed credit charge / missing token.
29543     * 
29544     * @apiExample Example usage:
29545     * {
29546     *         "ZPaymentFullLogs": {
29547     *             "cardnumber": 1234567890123456,
29548     *             "expyy": 2022,
29549     *             "expmm": 12,
29550     *             "username": "John Doe",
29551     *             "zeusToken": "zeusTokenValue",
29552     *             "payment_plan_type": 1,
29553     *             "paymentHash": "paymentHash",
29554     *             "money": 100,
29555     *             "formType": 2,
29556     *             "retainIndiPlan": 1,
29557     *             "telno": "0363863975",
29558     *             "clientip": "192.168.1.1",
29559     *             "corporatePlan": "premium",
29560     *             "indiCorpType": 4
29561     *         },
29562     *         "token": "userToken",
29563     *         "cardToken": "cardToken",
29564     *         "payment_gateway_type": 1,
29565     *         "receivablePayment": 100,
29566     *         "appreciationReceivable": 100,
29567     *         "liveLessonReceivable": 100
29568     * }
29569     * 
29570     * @apiSuccessExample Success Response For zeus:
29571     * Redirects to {{ENV}}/mobapp/payment/mobapp_credit_charge_confirm
29572     * 
29573     * @apiSuccessExample Success Response For paypal:
29574     * Redirects to {{ENV}}/mobapp/payment/paypal_payment_credit_charge_confirm
29575     * 
29576     * @apiErrorExample Error Response:
29577     * Redirects to {{ENV}}/mobapp/retrypage
29578     * 
29579     * apiSampleRequest off
29580     */
29581    public function mobapp_corporate_change_individual_card_payment() {
29582        $this->response->disableCache();
29583        $this->blockWithdrawnSapuriToS('mobapp');
29584        $this->disablePageForSapuri('mobapp');
29585        // set variables
29586        $this->layout = 'mobapp';
29587        $urlParams = myTools::getMobappToken($_GET);
29588
29589        $logFileName = 'card_charge';
29590        $formType = Configure::read('payment_credit_force_charge');
29591        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType)); // get user data and validate
29592        $requestQuery = $this->request->query;
29593        $apiToken = $requestQuery['token'];
29594        $paymentPlanId = Configure::read('payment_plans.premium_plan');
29595        $cardToken = isset($requestQuery['cardToken']) ? $requestQuery['cardToken'] : '';
29596        $memKey = 'mobappUserCreditChargeInfo_'.$apiToken;
29597        $userDataArr = $userData['User'];
29598        $corporateChargeMemData = array();
29599        $requestData = $this->request->data;
29600
29601        $userObj = new UserTable($userDataArr);
29602        $fromPage = !empty($this->request->query('from_page')) ? $this->request->query('from_page') : 'reservation';
29603        if (
29604            $fromPage != 'tip' && 
29605            !empty($userData['User']['corporate_id']) && 
29606            in_array($userObj->getMembershipTypeIndex(), Configure::read('common_corporate_payment_memberships'))
29607        ) {
29608            return $this->redirect(myTools::getUrl() . '/mobapp/common_corporate_payment?type=' .Configure::read('payment_url_type.corporate_type.corporate_change_individual_card_payment'). '&token=' . $apiToken . '&from_page=' . $fromPage);
29609        }
29610
29611        // - validate corp standard and premium user if bank and card
29612        if(!in_array($userObj->getMembershipTypeIndex(), Configure::read('corp_personal_card_payment_valid_memberships'))){
29613            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
29614        }
29615
29616        // get premium payment plan data
29617        $paymentData = $this->PaymentPlanPrice->getPaymentData(array(
29618            'currencyCode' => $userDataArr['currency_code'],
29619            'paymentPlanId' => $paymentPlanId,
29620            'logFileName' => $logFileName
29621        ));
29622
29623        if (!$paymentData) {
29624            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
29625        }
29626
29627        $amount = $paymentData['amount'];
29628        $fAmount = $paymentData['fAmount'];
29629        $retainIndiPlan = null;
29630        $corporateIndiUser = false;
29631
29632        // if corporate user
29633        if (isset($userDataArr['corporate_id']) && $userDataArr['corporate_id'] && isset($userDataArr['payment_plan_id'])) {
29634            
29635            // NJ-28462 Organize the re-enrollment behavior after corporate plan end From bug ticket
29636            $cpData = $this->getCorporatePaymentPlan($userDataArr);
29637            if (!$cpData) {
29638                return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
29639            }
29640            $corporateIndiUser = $cpData;
29641
29642            // check if corporate user retain as individual plan using new card
29643            if (!$retainIndiPlan = isset($requestQuery['retainIndiPlan']) ? $requestQuery['retainIndiPlan'] : null) {
29644                // check if corporate user retain as individual plan using existing card
29645                $retainIndiPlan = isset($requestData['ZPaymentFullLogs']['retainIndiPlan']) ? $requestData['ZPaymentFullLogs']['retainIndiPlan'] : null;
29646            }
29647
29648            if ($retainIndiPlan) {
29649                // get corporate user individual payment plan data
29650                if ($corporateChargeMemData = $this->memcache->get('mobappCreditChargeCorporateData_' . $userDataArr['id'])) {
29651                    $formType = myTools::getCorporateCompanyCardFormType($corporateChargeMemData['paymentPlanId']);
29652                    $amount = (int)$corporateChargeMemData['paymentAmount'];
29653                    $fAmount = $corporateChargeMemData['fAmount'];
29654                }
29655            }
29656        }
29657
29658        // - set receivable 
29659        $receivablePayment =  $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id']);
29660
29661        // get live lesson payment receivable
29662        $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('appreciation_data.payment_element_type'));
29663
29664        // get live lesson payment receivable
29665        $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('payment_element_type.live'));
29666
29667        $mobappCorpIndividualData = array(
29668            'apiToken' => $apiToken,
29669        );
29670        $this->corpIndividualData($userDataArr,$mobappCorpIndividualData);
29671
29672        // check if post
29673        if ($this->request->is('post')) {
29674            $data = $this->request->data;
29675
29676            $isLitePlanFlg = false;
29677
29678            if (
29679                isset($data['ZPaymentFullLogs']['payment_plan_type']) && 
29680                !$corporateIndiUser
29681            ) {
29682
29683                $isLitePlan = $isLitePlanFlg = ((int) $data['ZPaymentFullLogs']['payment_plan_type']  == 1) ? true : false;
29684                if ($isLitePlan) {
29685                    $_plan_id = Configure::read('payment_plans.light_plan');
29686                    $formType = myTools::getLitePlanUserFormType($_plan_id);
29687                }else{
29688                    $_plan_id = Configure::read('payment_plans.premium_plan');
29689                    $formType = Configure::read('payment_credit_force_charge');
29690                }
29691
29692                // fetch light plan description
29693                $litePlanData = $this->PaymentPlanPrice->getPaymentData(array(
29694                    'currencyCode' => $userDataArr['currency_code'],
29695                    'paymentPlanId' => $_plan_id,
29696                    'logFileName' => 'card_reregister'
29697                ));
29698
29699                if (!$litePlanData) {
29700                    return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
29701                }
29702
29703                // update payment plan data 
29704                $paymentData = $litePlanData;
29705
29706                $userDataArr['paymentAmount'] = $paymentData['amount'];
29707                $userDataArr['price_id'] = $paymentData['priceId'];
29708                $userDataArr['payment_plan_id'] = $paymentData['paymentPlanId'];
29709
29710                // add reserve payment receivable
29711                $userDataArr['paymentAmount'] +=  $receivablePayment;
29712
29713                // add appreciation payment receivable
29714                $userDataArr['paymentAmount'] +=  $appreciationReceivable;
29715
29716                // add live lesson payment receivable
29717                $userDataArr['paymentAmount'] +=  $liveLessonReceivable;
29718            
29719            
29720                // - update form type 
29721                $data['formType'] = $formType;
29722
29723                // redirect to retry page if failed to create payment transaction
29724                if (!$npt = $this->createPaymentTransaction($formType, $userDataArr)) {
29725                    return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
29726                }
29727
29728                // update payment hash , form type and money
29729                $data['ZPaymentFullLogs']['paymentHash'] = $npt['payment_hash'];
29730                $data['ZPaymentFullLogs']['money'] = $litePlanData['amount'];
29731                $data['ZPaymentFullLogs']['formType'] = $formType;
29732
29733            }else{
29734                $npt = true;
29735            }
29736
29737            if (
29738                $corporateIndiUser && 
29739                isset($data['ZPaymentFullLogs']['payment_plan_type']) && 
29740                (int) $data['ZPaymentFullLogs']['payment_plan_type'] == 1
29741            ) {
29742    
29743                $isLitePlanFlg = true;
29744
29745                $_plan_id = Configure::read('payment_plans.light_plan');
29746                $formType = myTools::getLitePlanUserFormType($_plan_id);
29747
29748                $data['token'] = $apiToken;
29749                $data['ZPaymentFullLogs']['telno'] = Configure::read('credit.default_telno');
29750                $data['ZPaymentFullLogs']['clientip'] = Configure::read('ZEUS_clientip');
29751                $data['ZPaymentFullLogs']['corporatePlan'] = $data['corporatePlan'];
29752                $data['cardToken'] = $cardToken;
29753
29754                if($corporateIndiUser['corporateIndiUser'] && isset($data['corporatePlan'])) {
29755                    if($data['corporatePlan'] == 'light') {
29756                        $cpData = $this->getCorporatePaymentPlan($userDataArr,array('corporate_type' => 4));
29757                        $data['ZPaymentFullLogs']['indiCorpType'] = 4;
29758                    } else if($data['corporatePlan'] == 'premium') {
29759                        $cpData = $this->getCorporatePaymentPlan($userDataArr,array('corporate_type' => 2));
29760                        $data['ZPaymentFullLogs']['indiCorpType'] = 2;
29761                    } else {
29762                        $cpData = $this->getCorporatePaymentPlan($userDataArr,array('corporate_type' => 1));
29763                        $data['ZPaymentFullLogs']['indiCorpType'] = 1;
29764                    }
29765                    $data['ZPaymentFullLogs']['formType'] = $formType = myTools::getCorporateCompanyCardFormType($cpData['paymentPlanId']);
29766                    $corpIndiPrices = $this->memcache->get('mobappcorporateIndiPrices_'.$userDataArr['api_token']);
29767                    $corpIndiPrices[$data['corporatePlan']]['plan_type'] = $data['ZPaymentFullLogs']['indiCorpType'];
29768                    $amount = (int)$corpIndiPrices[$data['corporatePlan']]['paymentAmount'];
29769                    $fAmount = $corpIndiPrices[$data['ZPaymentFullLogs']['corporatePlan']]['fAmount'];
29770    
29771                    $this->memcache->set(array(
29772                        'key' => 'mobappCreditChargeCorporateData_' . $userDataArr['id'],
29773                        'value' => $corpIndiPrices[$data['ZPaymentFullLogs']['corporatePlan']],
29774                        'expire' => 3600 // 1 hour
29775                    ));
29776    
29777                    $corporateChargeMemData = $this->memcache->get('mobappCreditChargeCorporateData_' . $userDataArr['id']);
29778    
29779                    // corporate light
29780                    if (
29781                        $corporateChargeMemData['plan_type'] == Configure::read('corporate_type.light') &&
29782                        isset($corporateChargeMemData['lessonFee']) &&
29783                        isset($corporateChargeMemData['basicFee'])
29784                    ) {
29785                        $userDataArr['lesson_fee'] = (int)$corporateChargeMemData['lessonFee'];
29786                        $userDataArr['basic_fee'] = (int)$corporateChargeMemData['basicFee'];
29787                    // standard or premium
29788                    } else {
29789                        if (isset($corporateChargeMemData['cprAmount']) && isset($corporateChargeMemData['cprDiscount'])) {
29790                            $userDataArr['cprAmount'] = (int)$corporateChargeMemData['cprAmount'];
29791                            $userDataArr['cprDiscount'] = (int)$corporateChargeMemData['cprDiscount'];
29792                        }
29793                    }
29794    
29795                    $userDataArr['corporateSettlementType'] = Configure::read('corporate_settlement_types.force_charge_payment');
29796                    $userDataArr['paymentAmount'] = $amount;
29797                    $userDataArr['price_id'] = $cpData['priceId'];
29798                    $userDataArr['payment_plan_id'] = $cpData['paymentPlanId'];
29799                    $userDataArr['corporate_type'] = $data['ZPaymentFullLogs']['indiCorpType'];
29800                    $formType = myTools::getCorporateCompanyCardFormType($cpData['paymentPlanId']);
29801    
29802                    $membershipTypes = UserTable::getEngMembershipTypeData();
29803                    $userDataArr['statusAfter'] =  myTools::getCorporateUserMembershipStatusName($membershipTypes, $userDataArr['payment_plan_id']);
29804    
29805                    $userTable = new UserTable($userDataArr);
29806                    // add statusBefore and statusAfter if free "Trial not yet conducted"
29807                    if ($userTable->getMembershipTypeIndex() == 13) {
29808                        $userDataArr['statusBefore'] = $membershipTypes[13];
29809                        $userDataArr['statusAfter'] = myTools::getCorporateUserMembershipStatusName($membershipTypes, $userDataArr['payment_plan_id']);
29810                    }
29811    
29812                    if ($retainIndiPlan) {
29813                        $data['ZPaymentFullLogs']['retainIndiPlan'] = $retainIndiPlan;
29814                    }
29815    
29816                    if ($corporateIndiUser && $corporateChargeMemData) {
29817                        // save new card charge token to memcache
29818                        $this->memcache->set(array(
29819                            'key' => 'card-charge-'.$apiToken,
29820                            'value' => $cardToken,
29821                            'expire' => 3600
29822                        ));
29823                    }
29824    
29825                    // add reserve payment receivable
29826                    $userDataArr['paymentAmount'] +=  $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id']);
29827    
29828                    // add appreciation payment receivable
29829                    $userDataArr['paymentAmount'] +=  $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('appreciation_data.payment_element_type'));
29830    
29831                    // add live lesson payment receivable
29832                    $userDataArr['paymentAmount'] +=  $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('payment_element_type.live'));
29833    
29834                    // redirect to retry page if failed to create payment transaction
29835                    if (!$pt = $this->createPaymentTransaction($formType, $userDataArr)) {
29836                        return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
29837                    }
29838    
29839                    $data['ZPaymentFullLogs']['paymentHash'] = $pt['payment_hash'];
29840    
29841                } // End of Check Corporate Individual
29842
29843                // NJ-25522: Skip confirm page if using 3D secure challenge
29844                $zeus3DSecureChallengeFlg = $this->memcache->get('zeus3DSecureChallengeFlg_' . $userDataArr['id']);
29845
29846                if ($zeus3DSecureChallengeFlg) {
29847                    // unset previously set tokens
29848                    $this->unsetTokenMobapp($apiToken, 'card-charge-');
29849
29850                    $formType = isset($data['ZPaymentFullLogs']['formType']) ? $data['ZPaymentFullLogs']['formType'] : $formType;
29851
29852                    // if corporate credit charge
29853                    if (
29854                        $formType != Configure::read('payment_credit_force_charge') && 
29855                        !$isLitePlanFlg
29856                    ) {
29857                        $data['ZPaymentFullLogs']['money'] = $fAmount;
29858                    }
29859
29860                    $totalReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id']) + $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('appreciation_data.payment_element_type')) + $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('payment_element_type.live'));
29861
29862                    $data['ZPaymentFullLogs']['money'] += $totalReceivable;
29863                    $this->Session->write('mobapp_show_welcome_back_modal',true);
29864                    //process zeus card
29865                    $this->zeus_card_process_mobapp(array(
29866                        'data' => $data,
29867                        'form_type' => $formType,
29868                        'referrer' => array('controller' => 'Payment', 'action' => 'mobapp_credit_charge', '?' => array('token' => $apiToken)),
29869                        'api_token' => $apiToken
29870                    ));
29871                }
29872
29873                // delete memcache if exist
29874                if ($this->memcache->get($memKey)) {
29875                    $this->memcache->delete($memKey);
29876                }
29877
29878                // set memcache
29879                $this->memcache->set(array(
29880                    'key' => $memKey,
29881                    'value' => $data,
29882                    'expire' => 3600
29883                ));
29884                
29885                // fetch light plan description
29886                $litePlanData = $this->PaymentPlanPrice->getPaymentData(array(
29887                    'currencyCode' => $userDataArr['currency_code'],
29888                    'paymentPlanId' => $_plan_id,
29889                    'logFileName' => $logFileName
29890                ));
29891
29892                if (!$litePlanData) {
29893                    return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
29894                }
29895
29896                // update payment plan data 
29897                $paymentData = $litePlanData;
29898
29899                $userDataArr['paymentAmount'] = $paymentData['amount'];
29900                $userDataArr['price_id'] = $paymentData['priceId'];
29901                $userDataArr['payment_plan_id'] = $paymentData['paymentPlanId'];
29902
29903                // add reserve payment receivable
29904                $userDataArr['paymentAmount'] +=  $receivablePayment;
29905
29906
29907                // add appreciation payment receivable
29908                $userDataArr['paymentAmount'] +=  $appreciationReceivable;
29909
29910                // add live lesson payment receivable
29911                $userDataArr['paymentAmount'] +=  $liveLessonReceivable;
29912            
29913            
29914                // - update form type 
29915                $data['formType'] = $formType;
29916                
29917                // redirect to retry page if failed to create payment transaction
29918                if (!$npt = $this->createPaymentTransaction($formType, $userDataArr)) {
29919                    return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
29920                }
29921
29922                // update payment hash
29923                $data['ZPaymentFullLogs']['paymentHash'] = $npt['payment_hash'];
29924                $data['ZPaymentFullLogs']['formType'] = $formType;
29925                $data['ZPaymentFullLogs']['money'] = $litePlanData['amount'];
29926                $data['ZPaymentFullLogs']['retainIndiPlan'] = 0;
29927            }
29928
29929
29930                
29931            // redirect to paypal confirm page if payment gateway selected is paypal
29932            if ($data['payment_gateway_type'] == Configure::read('card_company.paypal')) {
29933                $data['paymentPlanData'] = $paymentData;
29934                $data['receivablePayment'] = $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id']);
29935                $data['appreciationReceivable'] = $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('appreciation_data.payment_element_type'));
29936                $data['liveLessonReceivable'] = $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('payment_element_type.live'));
29937                $data['formType'] = $formType;
29938                $this->memcache->set(array(
29939                    'key' => 'mobappPaypalPaymentCreditChargeData_' . $apiToken,
29940                    'value' => $data,
29941                    'expire' => 3600 // 1 hour
29942                ));
29943                return $this->redirect(myTools::getUrl() . '/mobapp/payment/paypal_payment_credit_charge_confirm?token=' . $apiToken);
29944            }
29945
29946            // delete payment gateway type memcache
29947            $this->memcache->delete('mobappCreditChargePaymentGatewayType_' . $apiToken);
29948
29949            $data['token'] = $apiToken;
29950            $data['ZPaymentFullLogs']['telno'] = Configure::read('credit.default_telno');
29951            $data['ZPaymentFullLogs']['clientip'] = Configure::read('ZEUS_clientip');
29952            $data['cardToken'] = $cardToken;
29953
29954            // NJ-25522: Skip confirm page if using 3D secure challenge
29955            $zeus3DSecureChallengeFlg = $this->memcache->get('zeus3DSecureChallengeFlg_' . $userDataArr['id']);
29956
29957            if ($zeus3DSecureChallengeFlg) {
29958                // unset previously set tokens
29959                $this->unsetTokenMobapp($apiToken, 'card-charge-');
29960
29961                $formType = isset($data['ZPaymentFullLogs']['formType']) ? $data['ZPaymentFullLogs']['formType'] : $formType;
29962
29963                // if corporate credit charge
29964                if (
29965                        $formType != Configure::read('payment_credit_force_charge') && 
29966                        !$isLitePlanFlg
29967                ) {
29968                    $data['ZPaymentFullLogs']['money'] = $fAmount;
29969                }
29970
29971                $totalReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id']) + $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('appreciation_data.payment_element_type')) + $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('payment_element_type.live'));
29972
29973                $data['ZPaymentFullLogs']['money'] += $totalReceivable;
29974                $this->Session->write('mobapp_show_welcome_back_modal',true);
29975                //process zeus card
29976                $this->zeus_card_process_mobapp(array(
29977                    'data' => $data,
29978                    'form_type' => $formType,
29979                    'referrer' => array('controller' => 'Payment', 'action' => 'mobapp_credit_charge', '?' => array('token' => $apiToken)),
29980                    'api_token' => $apiToken
29981                ));
29982            }
29983
29984            // delete memcache if exist
29985            if ($this->memcache->get($memKey)) {
29986                $this->memcache->delete($memKey);
29987            }
29988
29989            // set memcache
29990            $this->memcache->set(array(
29991                'key' => $memKey,
29992                'value' => $data,
29993                'expire' => 3600
29994            ));
29995
29996            return $this->redirect(myTools::getUrl() . '/payment/mobapp_credit_charge_confirm'.$urlParams);
29997            
29998        } else {
29999            // delete payment gateway type memcache
30000            $this->memcache->delete('mobappCreditChargePaymentGatewayType_' . $apiToken);
30001
30002            $this->set('data', $this->memcache->get($memKey));
30003        }
30004
30005        // if not retain indi plan
30006        if (!$corporateIndiUser) {
30007            $userDataArr['paymentAmount'] = $paymentData['amount'];
30008            $userDataArr['price_id'] = $paymentData['priceId'];
30009            $userDataArr['payment_plan_id'] = $paymentData['paymentPlanId'];
30010
30011            $data['ZPaymentFullLogs']['formType'] = $formType;
30012
30013            // add reserve payment receivable
30014            $userDataArr['paymentAmount'] +=  $receivablePayment;
30015
30016            // add appreciation payment receivable
30017            $userDataArr['paymentAmount'] +=  $appreciationReceivable;
30018
30019            // add live lesson payment receivable
30020            $userDataArr['paymentAmount'] +=  $liveLessonReceivable;
30021
30022            // redirect to retry page if failed to create payment transaction
30023            if (!$pt = $this->createPaymentTransaction($formType, $userDataArr)) {
30024                return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
30025            }
30026
30027            $data['ZPaymentFullLogs']['paymentHash'] = $pt['payment_hash'];
30028
30029        }
30030
30031        // delete memcache if exist
30032        if ($this->memcache->get($memKey)) {
30033            $this->memcache->delete($memKey);
30034        }
30035
30036        // set memcache
30037        $this->memcache->set(array(
30038            'key' => $memKey,
30039            'value' => $data,
30040            'expire' => 3600
30041        ));
30042
30043        $users_detail = $userObj->individualCardFailFlg();
30044        $this->set('individual_card_fail_flg', $users_detail['individual_card_fail_flg'] ?? 0);
30045        $this->getAndSetCardInfo($userDataArr);
30046        $this->setSupportPayPal($userDataArr);
30047        $this->set('userData', $userDataArr);
30048        $this->set('apiToken', $apiToken);
30049        $this->set('zeusTransactionFlag', true);
30050        $this->set('title_for_layout', '再入会');
30051        $this->set('paypalUserData', $userDataArr);
30052        $this->set('userApiToken', $apiToken);
30053        $this->render(myTools::getDeviceUrl().'Payment/corporate_change_individual_card_payment');
30054    }
30055
30056    /**
30057     * ~NJ-29078 - process child receivable payment 
30058     * @param array $familyArr, array $parentArr
30059     */
30060    public function processChildReceivablePayment($familyArr = [], $parentArr = []) {
30061        $this->logFileName = 'family_plan';
30062        $curlPayment = "";
30063
30064        if (!$pt = $this->Payment->setUpWithdrawTransaction($familyArr, $this->logFileName)) {
30065            return false;
30066        }
30067
30068        // ~if zero receivable just return success
30069        if (isset($pt['totalAmount']) && $pt['totalAmount'] == 0) {
30070            $this->log(__METHOD__ . ' No receivable to process' . json_encode($pt), $this->logFileName);
30071            $curlPayment = "success_order";
30072            return $curlPayment;
30073        }
30074
30075        $familyObj = new UserTable($familyArr);
30076        $parentObj = new UserTable($parentArr);
30077
30078        if ($parentObj->card_company == Configure::read('card_company.zeus')){
30079            $data = array(
30080                'clientIp' => PaymentTable::getClientIpByCompanyId($parentObj->card_company),
30081                'email' => $parentObj->email,
30082                'sendId' => $parentObj->id,
30083                'money' => $pt['totalAmount'],
30084                'paymentHash' => $pt['payment_hash']
30085            );
30086            // ~process
30087            $curlPayment = $this->ZCharge->charge_with_regsterd_card(json_encode($data));
30088            $curlPayment = PaymentTable::checkPaymentResult($curlPayment);
30089        } else if ($parentObj->card_company == Configure::read('card_company.worldpay')) {
30090            $paymentMethodType = myTools::getWPPaymentMethodType($parentObj->card_brand, 'payment');
30091            $merchantCode = myTools::getWPMerchantCode($paymentMethodType);
30092            $paymentHash = $pt['payment_hash'];
30093            $paymentMethod = explode('_', $paymentMethodType);
30094            $paymentMethod = isset($paymentMethod[0]) ? $paymentMethod[0] : null;
30095            $currencyExponents = Configure::read('worldpay.currency_exponents');
30096            $exponent = $currencyExponents[$parentObj->currency_code];
30097            // get amount with checking currency exponent
30098            $amountArr = myTools::wpGetAmount($exponent, $pt['totalAmount']);
30099            $wpAmount = $amountArr['wpAmount'];
30100
30101            $decodePaymentParams= json_decode($pt['payment_params']);
30102            $paymentFormType = $decodePaymentParams->formType;
30103
30104            $wpParams = array(
30105                'merchantCode' => $merchantCode,
30106                'orderCode' => $paymentHash,
30107                'description' => 'Child Withdrawal Receivables',
30108                'currencyCode' => $parentObj->currency_code,
30109                'exponent' => $exponent,
30110                'amount' => $wpAmount,
30111                'cardToken' => $parentObj->card_token,
30112                'email' => $parentObj->email,
30113                'authenticatedShopperId' => $parentObj->id,
30114                'xmlName' => 'direct_payment_with_token',
30115                'shopperIpAddress' => $_SERVER["REMOTE_ADDR"],
30116                'wpTransactionIdentifier' => $parentObj->wp_transaction_identifier,
30117                'paymentMethod' => $paymentMethod
30118            );
30119
30120            $updateData = array(
30121                'id' => $pt['id'],
30122                'fields' => array('payment_params' => $wpParams)
30123            );
30124
30125            if (!$this->PaymentTransaction->updateWPPaymentTransaction($updateData)) {
30126                $this->log(__METHOD__ . ' Failed to update payment transaction' . json_encode($updateData), $this->logFileName);
30127                $this->log(__METHOD__ . ' Worldpay: ' . $parentObj->id . ' - Failed to update payment transaction --> ' . json_encode($updateData), 'error');
30128            } else {
30129                if (!$pt = $this->PaymentTransaction->getWPPaymentTransaction($paymentHash)) {
30130                    return false;
30131                }
30132            }
30133
30134            $this->log(__METHOD__ . ' Worldpay: ' . $parentObj->id . ' - Initial updateWPPaymentTransaction --> ' . json_encode($updateData), 'error');
30135
30136            // ~process
30137            $res = wpPaymentService::directPayment($wpParams);
30138
30139            $updateData = array(
30140                'id' => $pt['id'],
30141                'fields' => array('response_text' => array('directPayment_response' => $res))
30142            );
30143
30144            if (!$this->PaymentTransaction->updateWPPaymentTransaction($updateData)) {
30145                $this->log(__METHOD__ . ' Failed to update payment transaction' . json_encode($updateData), $this->logFileName);
30146                $this->log(__METHOD__ . ' Worldpay: ' . $parentObj->id . ' - Failed to update payment transaction --> ' . json_encode($updateData), 'error');
30147            } else {
30148                $this->log(__METHOD__ . ' Worldpay: ' . $parentObj->id . ' - additional updateWPPaymentTransaction --> ' . json_encode($updateData), 'error');
30149            }
30150            
30151            if (!myTools::checkIfWPPaymentResponseIsAuthorised($res)) {
30152                $curlPayment = "";
30153                $this->log(__METHOD__ . ' Not authorised payment worldpay' . $familyObj->id, $this->logFileName);
30154                $this->log(__METHOD__ . ' Worldpay: ' . $parentObj->id . ' - Not authorised payment worldpay --> ' . $familyObj->id, 'error');
30155            }else{
30156                $curlPayment = "success_order";
30157            }
30158        } else if ($parentObj->card_company == Configure::read('card_company.aftee')) {
30159            $paymentMethodType = myTools::getWPPaymentMethodType($parentObj->card_brand, 'payment');
30160            $merchantCode = myTools::getWPMerchantCode($paymentMethodType);
30161            $paymentHash = $pt['payment_hash'];
30162            $paymentMethod = explode('_', $paymentMethodType);
30163            $paymentMethod = isset($paymentMethod[0]) ? $paymentMethod[0] : null;
30164            $decodePaymentParams= json_decode($pt['payment_params']);
30165            $paymentFormType = $decodePaymentParams->formType;          
30166
30167            $afteeParams = array(
30168                'merchantCode' => $merchantCode,
30169                'orderCode' => $paymentHash,
30170                'description' => 'Family Plan Registration',
30171                'currencyCode' => $parentObj->currency_code,
30172                'amount' => $pt['totalAmount'],
30173                'cardToken' => $parentObj->card_token,
30174                'email' => $parentObj->email,
30175                'authenticatedShopperId' => $parentObj->id,
30176                'shopperIpAddress' => $_SERVER["REMOTE_ADDR"],
30177                'afteeTransactionIdentifier' => $parentObj->aftee_transaction_identifier,
30178                'paymentMethod' => $paymentMethod
30179            );
30180
30181            $updateData = array(
30182                'id' => $pt['id'],
30183                'fields' => array('payment_params' => $afteeParams)
30184            );
30185
30186            if (!$this->PaymentTransaction->updateAfteePaymentTransaction($updateData)) {
30187                $this->log(__METHOD__ . ' Failed to update payment transaction' . json_encode($updateData), $this->logFileName);
30188            }else{
30189                if (!$pt = $this->PaymentTransaction->getAfteePaymentTransaction($paymentHash)) {
30190                    return false;
30191                }
30192            }
30193
30194            // ~process
30195            $afteeParams = array(
30196                'parent' =>  $parentObj,
30197                'child' =>  $familyObj,
30198                'paymentTransaction' => $pt,
30199                'appreciationFlg' => $familyObj->allow_appreciation_flg,
30200                'tipAmount' => myTools::stringToFloat($familyObj->tip_max_amount)
30201            );
30202
30203            $curlPayment = $this->processChildAfteePayment($afteeParams);
30204        } elseif ($parentObj->card_company == Configure::read('card_company.paypal')) {
30205            $paypalParams = array(
30206                'parent' => $parentObj,
30207                'child' => $familyObj,
30208                'paymentTransaction' => $pt,
30209                'memberStatus' => 'exist'
30210            );
30211
30212            $curlPayment = $this->processChildPaypalPayment($paypalParams);
30213        }
30214
30215        return $curlPayment;
30216    }
30217
30218    // ~NJ-29078 - Process Paypal Payment
30219    private function processChildPaypalPayment($params = array()) {
30220        if (
30221            !isset($params['child']) ||
30222            !isset($params['parent']) ||
30223            !isset($params['paymentTransaction'])
30224        ) {
30225            $this->log('__METHOD__' . ' missing parameter(s). --> ' . json_encode($params), $this->logFileName);
30226            return false;
30227        }
30228
30229        // ~check for family parent 
30230        $child = $params['child'];
30231        $parent = $params['parent'];
30232        $pt = $params['paymentTransaction'];
30233        $memberStatus = $params['memberStatus'];
30234
30235        $paymentHash = $pt['payment_hash'];
30236        $ptPassword = $pt['password'];
30237        $ptParams = json_decode($pt['payment_params'], true);
30238
30239        $formType = $ptParams['formType'];
30240        $currencyCode = $ptParams['currencyCode'];
30241        $paymentPlanId = $ptParams['paymentPlanId'];
30242        $priceId = $ptParams['priceId'];
30243        $paymentType = Configure::read('payment_types.payment_receivable');
30244        $platform = $ptParams['platform'];
30245
30246        $membershipStatusIndex = UserTable::getStudentMembershipStatus($child->id);
30247        $currencyId = Configure::read('default.settlement_currency_id'); // set currency id to jpy
30248        $cardCompany = Configure::read('card_company.paypal');
30249        $dateTimeNow = date('Y-m-d H:i:s');
30250
30251        $reservationReceivableAmount = isset($ptParams['reservationReceivableAmount']) ? $ptParams['reservationReceivableAmount'] : 0;
30252        $appreciationReceivableAmount = isset($ptParams['appreciationReceivableAmount']) ? $ptParams['appreciationReceivableAmount'] : 0;
30253        $liveReceivableAmount = isset($ptParams['liveReceivableAmount']) ? $ptParams['liveReceivableAmount'] : 0;
30254
30255
30256        if (!class_exists('PayPal')) {
30257            App::import('Lib', 'PayPal');
30258        }
30259
30260        $PayPal = new PayPal();
30261        $accessTokenData = $PayPal->getAccessToken();
30262
30263        $totalAmount = (int) ($reservationReceivableAmount + $appreciationReceivableAmount + $liveReceivableAmount);
30264
30265        $paypalParams = array(
30266            'ptId' => $pt['id'],
30267            'paypalData' => array('accessTokenData' => $accessTokenData),
30268            'userId' => $pt['id'],
30269            'money' => $totalAmount,
30270            'formType' => $formType,
30271            'priceId' => $priceId,
30272            'paymentId' => $paymentPlanId,
30273            'paymentType' => $paymentType
30274        );
30275
30276        // break if error
30277        if (!isset($accessTokenData['access_token'])) {
30278                $this->log(__METHOD__ . ' paypal error --> ' . json_encode($accessTokenData) . ' --> ' . json_encode($params), $this->logFileName);
30279            return ;
30280        }
30281
30282        $createOrderParams = array(
30283            'accessToken' => $accessTokenData['access_token'],
30284            'paypalRequestId' => $pt['id'],
30285            'intent' => 'CAPTURE',
30286            'paymentHash' => $paymentHash,
30287            'userId' => $parent->id,
30288            'currencyCode' => $currencyCode,
30289            'amount' => $totalAmount,
30290            'billingAgreementId' => $parent->paypal_billing_agreement_id
30291        );
30292
30293        // add mock application code
30294        if (isset($request['mockResponse'])) {
30295            $createOrderParams['mockResponse'] = $request['mockResponse'];
30296        }
30297
30298        $curlPayment = $PayPal->createOrder($createOrderParams);
30299        $paypalParams['paypalData']['createOrder'] = $curlPayment;
30300        $paymentSuccess = isset($curlPayment['status']) && $curlPayment['status'] == 'COMPLETED' ? true : false;
30301
30302        if (!$paymentSuccess) {
30303            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $parent->id, 'Paypal process child payment - failed to create order', $ptParams, $createOrderParams);
30304            $this->log(__METHOD__ . ' paypal error --> ' . json_encode($curlPayment) . ' --> ' . json_encode($params), $this->logFileName);
30305            return ;
30306        }
30307
30308        // create payment
30309        $savePaymentArr = array(
30310            'user_id' => $child->id,
30311            'amount' => $totalAmount,
30312            'status' => 1,
30313            'reference_id' => $child->id,
30314            'payment_transaction_password' => $ptPassword,
30315            'card_company' => $cardCompany,
30316            'param1' => json_encode($paypalParams),
30317            'form_type' => $formType,
30318            'ordd' => $paymentHash,
30319            'transaction_code' => $paymentHash,
30320            'currency_id' => $currencyId,
30321            'currency_code' => $currencyCode,
30322            'payment_id' => $paymentPlanId,
30323            'price_id' => $priceId,
30324            'payment_type' => $paymentType
30325        );
30326
30327        $this->Payment->clear();
30328        $this->Payment->create();
30329        $this->Payment->set($savePaymentArr);
30330        $this->Payment->validate = array();
30331
30332        // update/add user`s settlement amount
30333        $this->User->updateUserPayments($savePaymentArr);
30334
30335        // set payment_id
30336        $paymentSaveID = $this->Payment->id;
30337        $data = array('payment_id' => $paymentSaveID);
30338        $paymentType = Configure::read('payment_types.payment_receivable');
30339
30340        // reservation receivable
30341        if ($reservationReceivableAmount > 0) {
30342            $savePaymentArr = array(
30343                'user_id' => $child->id,
30344                'amount' => $reservationReceivableAmount,
30345                'status' => 1,
30346                'type_id' => 1,
30347                'reference_id' => $child->id,
30348                'card_company' => $cardCompany,
30349                'param1' => json_encode($data),
30350                'form_type' => Configure::read('payment_credit_receivable'),
30351                'ordd' => $paymentHash,
30352                'transaction_code' => $paymentHash,
30353                'currency_id' => $currencyId,
30354                'currency_code' => $currencyCode,
30355                'payment_id' => $paymentPlanId,
30356                'price_id' => $priceId,
30357                'payment_type' => $paymentType
30358            );
30359
30360            // create new payment for reservation receivable
30361            $this->Payment->clear();
30362            $this->Payment->create();
30363            $this->Payment->set($savePaymentArr);
30364            if (!$this->Payment->save()) {
30365                $this->log(__METHOD__ . ' Failed to save payment data for reservation receivable.' . json_encode($savePaymentArr), $logFileName);
30366                $dataSource->rollback();
30367                return ;
30368            }
30369
30370            // set payment_id
30371            $rrPaymentID = $this->Payment->id;
30372
30373            //update/add user`s settlement amount
30374            $this->User->updateUserPayments($savePaymentArr);
30375
30376            // set payment receivable statuses to 2 - received
30377            $this->PaymentReceivable->updateReceivableReservationPayment(
30378                $child->id,
30379                array(
30380                    'status' => 2,
30381                    'payment_id' => $rrPaymentID,
30382                    'payment_collection_date' => $dateTimeNow,
30383                    'card_company' => $cardCompany,
30384                    'payment_plan_id' => $paymentPlanId,
30385                    'membership_type_index' => $membershipStatusIndex
30386                ),
30387                array(
30388                    'PaymentReceivable.user_id' => $child->id,
30389                    'PaymentReceivable.status' => 0,
30390                    'PaymentReceivable.payment_element_type' => Configure::read('payment_element_type.reservation'),
30391                    'PaymentReceivable.created <=' => $dateTimeNow
30392                )
30393            );
30394        }
30395
30396        // appreciation receivable
30397        if ($appreciationReceivableAmount > 0) {
30398            $savePaymentArr = array(
30399                'user_id' => $child->id,
30400                'amount' => $appreciationReceivableAmount,
30401                'status' => 1,
30402                'type_id' => 1,
30403                'reference_id' => $child->id,
30404                'card_company' => $cardCompany,
30405                'param1' => json_encode($data),
30406                'form_type' => Configure::read('payment_credit_appreciation_receivable'),
30407                'ordd' => $paymentHash,
30408                'transaction_code' => $paymentHash,
30409                'currency_id' => $currencyId,
30410                'currency_code' => $currencyCode,
30411                'payment_id' => $paymentPlanId,
30412                'price_id' => $priceId,
30413                'payment_type' => $paymentType
30414            );
30415
30416            // create new payment for appreciation receivable
30417            $this->Payment->clear();
30418            $this->Payment->create();
30419            $this->Payment->set($savePaymentArr);
30420            if (!$this->Payment->save()) {
30421                $this->log(__METHOD__ . ' Failed to save payment data for appreciation receivable.' . json_encode($savePaymentArr), $logFileName);
30422                $dataSource->rollback();
30423                return ;
30424            }
30425
30426            // set payment_id
30427            $arPaymentID = $this->Payment->id;
30428
30429            //update/add user`s settlement amount
30430            $this->User->updateUserPayments($savePaymentArr);
30431
30432            // set payment receivable statuses to 2 - received
30433            $this->PaymentReceivable->updateReceivableReservationPayment(
30434                $child->id,
30435                array(
30436                    'status' => 2,
30437                    'payment_id' => $arPaymentID,
30438                    'payment_collection_date' => $dateTimeNow,
30439                    'card_company' => $cardCompany,
30440                    'payment_plan_id' => $paymentPlanId,
30441                    'membership_type_index' => $membershipStatusIndex
30442                ),
30443                array(
30444                    'PaymentReceivable.user_id' => $child->id,
30445                    'PaymentReceivable.status' => 0,
30446                    'PaymentReceivable.payment_element_type' => Configure::read('payment_element_type.appreciation'),
30447                    'PaymentReceivable.created <=' => $dateTimeNow
30448                )
30449            );
30450        }
30451
30452        // live receivable
30453        if ($liveReceivableAmount > 0) {
30454            $savePaymentArr = array(
30455                'user_id' => $child->id,
30456                'amount' => $liveReceivableAmount,
30457                'status' => 1,
30458                'type_id' => 1,
30459                'reference_id' => $child->id,
30460                'card_company' => $cardCompany,
30461                'param1' => json_encode($data),
30462                'form_type' => Configure::read('payment_live_lesson_receivable'),
30463                'ordd' => $paymentHash,
30464                'transaction_code' => $paymentHash,
30465                'currency_id' => $currencyId,
30466                'currency_code' => $currencyCode,
30467                'payment_id' => $paymentPlanId,
30468                'price_id' => $priceId,
30469                'payment_type' => $paymentType
30470            );
30471
30472            // create new payment for live receivable
30473            $this->Payment->clear();
30474            $this->Payment->create();
30475            $this->Payment->set($savePaymentArr);
30476            if (!$this->Payment->save()) {
30477                $this->log(__METHOD__ . ' Failed to save payment data for live receivable.' . json_encode($savePaymentArr), $logFileName);
30478                $dataSource->rollback();
30479                return ;
30480            }
30481
30482            // set payment_id
30483            $lrPaymentID = $this->Payment->id;
30484
30485            //update/add user`s settlement amount
30486            $this->User->updateUserPayments($savePaymentArr);
30487
30488            // set payment receivable statuses to 2 - received
30489            $this->PaymentReceivable->updateReceivableReservationPayment(
30490                $child->id,
30491                array(
30492                    'status' => 2,
30493                    'payment_id' => $lrPaymentID,
30494                    'payment_collection_date' => $dateTimeNow,
30495                    'card_company' => $cardCompany,
30496                    'payment_plan_id' => $paymentPlanId,
30497                    'membership_type_index' => $membershipStatusIndex
30498                ),
30499                array(
30500                    'PaymentReceivable.user_id' => $child->id,
30501                    'PaymentReceivable.status' => 0,
30502                    'PaymentReceivable.payment_element_type' => Configure::read('payment_element_type.live'),
30503                    'PaymentReceivable.created <=' => $dateTimeNow
30504                )
30505            );
30506        }
30507
30508        $fields = array('status' => 1);
30509        if (isset($paypalParams)) {
30510            $fields['response_text'] = array('paypal_response' => $paypalParams);
30511        }
30512
30513        // update payment transaction
30514        $this->PaymentTransaction->updateWPPaymentTransaction(array('id' => $ptId, 'fields' => $fields));
30515
30516        return 'success_order';
30517
30518    }
30519    
30520    // ~NJ-29078 - Process Aftee Payment
30521    private function processChildAfteePayment($params = array()) {
30522        if (
30523            !isset($params['child']) ||
30524            !isset($params['parent']) ||
30525            !isset($params['paymentTransaction'])
30526        ) {
30527            $this->log('__METHOD__' . ' missing parameter(s). --> ' . json_encode($params), $this->logFileName);
30528            return false;
30529        }
30530
30531        $parent = $params['parent'];
30532        $child = $params['child'];
30533        $pt = $params['paymentTransaction'];
30534
30535        $ptId = $pt['id'];
30536        $ptPassword = $pt['password'];
30537        $ptParams = json_decode($pt['payment_params'], true);
30538
30539        $formType = $ptParams['formType'];
30540        $currencyCode = $ptParams['currencyCode'];
30541        $paymentPlanId = $ptParams['paymentPlanId'];
30542        $priceId = $ptParams['priceId'];
30543        $paymentType = $ptParams['paymentType'];
30544        $platform = $ptParams['platform'];
30545        $paymentHash = $ptParams['orderCode'];
30546        $afteeTransactionIdentifier = $ptParams['afteeTransactionIdentifier'];
30547
30548        $membershipStatusIndex = UserTable::getStudentMembershipStatus($child->id);
30549        $currencyId = Configure::read('default.settlement_currency_id'); // set currency id to jpy
30550        $cardCompany = Configure::read('card_company.aftee');
30551        $dateTimeNow = date('Y-m-d H:i:s');
30552
30553        $appreciationFlg = 0;
30554        $this->log(__METHOD__ . ' aftee debug --> ' . json_encode($params), $this->logFileName);
30555        $this->log(__METHOD__ . ' aftee debug --> ' . json_encode($pt), $this->logFileName);
30556        $this->log(__METHOD__ . ' aftee debug --> ' . $paymentHash, $this->logFileName);
30557
30558        // set transaction
30559        $dataSource = $this->Payment->getDataSource();
30560        $dataSource->begin();
30561
30562        // initial aftee amount
30563        $totalAmount = (int)$ptParams['paymentAmount'];
30564
30565        if ($totalAmount > 0) {
30566            if (isset($parent->aftee_transaction_identifier) && !empty($parent->aftee_transaction_identifier)) {
30567                $related_id = $parent->aftee_transaction_identifier;
30568            } else {
30569                $related_id = $afteeTransactionIdentifier;
30570            }
30571            
30572            // load PayPal class
30573            if (!class_exists('AfteePaymentService')) {
30574                App::import('Lib', 'AfteePaymentService');
30575            }
30576
30577            $afteeChecksumData = array(
30578                'shopItemId' => "AFTEE" . $formType,
30579                'itemName' => 'FamilyPlanRegistration',
30580                'itemPrice' => $totalAmount,
30581                'itemCount' => 1,
30582                'customerPhoneNumber' => $parent->phone_number,
30583                'customerEmail' => $parent->email,
30584                'shopTransactionNo' => $paymentHash,
30585                'userID' => $parent->id
30586            );
30587            $afteeService = new AfteePaymentService();
30588            $checksum = $afteeService->generateChecksum($afteeChecksumData, false);
30589            
30590
30591            $afteeData = array(
30592                'authentication_token' => $parent->card_token,
30593                'related_id' => $related_id,
30594                'checksum' => $checksum['checksum'],
30595                'shop_transaction_no' => $paymentHash,
30596                'transaction_options' => array(1)
30597            );
30598
30599            $afteePaymentData = array_merge($afteeData, $checksum['settlementData']);
30600
30601            // process Aftee direct payment
30602            $res = $afteeService->directPayment($afteePaymentData);
30603            $checkRes = json_decode($res, true);
30604            $this->log(__METHOD__ . ' aftee --> ' . json_encode($afteePaymentData) . ' --> ' . json_encode($checkRes), $this->logFileName);
30605
30606            if ( isset($checkRes['object']) && $checkRes['object'] == 'transaction') {
30607                $paymentSuccess = true;
30608            } else if ( !array_key_exists("object", $checkRes) || (isset($checkRes['object']) && $checkRes['object'] == 'error')) {
30609                $paymentSuccess = false;
30610            }
30611        } else {
30612            // zero payment
30613            $checkRes = array('aftee zero payment --> family plan registration');
30614            $paymentSuccess = true;
30615        }
30616
30617
30618        if (!$paymentSuccess) {
30619            $this->log(__METHOD__ . ' aftee error --> ' . json_encode($checkRes) . ' --> ' . json_encode($params), $this->logFileName);
30620            return;
30621        }
30622
30623        // payment history data amount
30624        $reservationReceivableAmount = isset($ptParams['reservationReceivableAmount']) ? $ptParams['reservationReceivableAmount'] : 0;
30625        $appreciationReceivableAmount = isset($ptParams['appreciationReceivableAmount']) ? $ptParams['appreciationReceivableAmount'] : 0;
30626        $liveReceivableAmount = isset($ptParams['liveReceivableAmount']) ? $ptParams['liveReceivableAmount'] : 0;
30627
30628        // create payment
30629        $savePaymentArr = array(
30630            'user_id' => $child->id,
30631            'status' => 1,
30632            'reference_id' => $child->id,
30633            'payment_transaction_password' => $ptPassword,
30634            'card_company' => $cardCompany,
30635            'param1' => json_encode($checkRes),
30636            'form_type' => $formType,
30637            'ordd' => $paymentHash,
30638            'transaction_code' => $paymentHash,
30639            'currency_id' => $currencyId,
30640            'currency_code' => $currencyCode,
30641            'payment_id' => $paymentPlanId,
30642            'price_id' => $priceId,
30643            'payment_type' => $paymentType
30644        );
30645
30646        $this->Payment->clear();
30647        $this->Payment->create();
30648        $this->Payment->set($savePaymentArr);
30649        $this->Payment->validate = array();
30650
30651        // update/add user`s settlement amount
30652        $this->User->updateUserPayments($savePaymentArr);
30653
30654        // set payment_id
30655        $paymentSaveID = $this->Payment->id;
30656        $data = array('payment_id' => $paymentSaveID);
30657        $paymentType = Configure::read('payment_types.payment_receivable');
30658
30659        // reservation receivable
30660        if ($reservationReceivableAmount > 0) {
30661            $savePaymentArr = array(
30662                'user_id' => $child->id,
30663                'amount' => $reservationReceivableAmount,
30664                'status' => 1,
30665                'type_id' => 1,
30666                'reference_id' => $child->id,
30667                'card_company' => $cardCompany,
30668                'param1' => json_encode($data),
30669                'form_type' => Configure::read('payment_credit_receivable'),
30670                'ordd' => $paymentHash,
30671                'transaction_code' => $paymentHash,
30672                'currency_id' => $currencyId,
30673                'currency_code' => $currencyCode,
30674                'payment_id' => $paymentPlanId,
30675                'price_id' => $priceId,
30676                'payment_type' => $paymentType
30677            );
30678
30679            // create new payment for reservation receivable
30680            $this->Payment->clear();
30681            $this->Payment->create();
30682            $this->Payment->set($savePaymentArr);
30683            if (!$this->Payment->save()) {
30684                $this->log(__METHOD__ . ' Failed to save payment data for reservation receivable.' . json_encode($savePaymentArr), $this->logFileName);
30685                $dataSource->rollback();
30686                return;
30687            }
30688
30689            // set payment_id
30690            $rrPaymentID = $this->Payment->id;
30691
30692            //update/add user`s settlement amount
30693            $this->User->updateUserPayments($savePaymentArr);
30694
30695            // set payment receivable statuses to 2 - received
30696            $this->PaymentReceivable->updateReceivableReservationPayment(
30697                $child->id,
30698                array(
30699                    'status' => 2,
30700                    'payment_id' => $rrPaymentID,
30701                    'payment_collection_date' => $dateTimeNow,
30702                    'card_company' => $cardCompany,
30703                    'payment_plan_id' => $paymentPlanId,
30704                    'membership_type_index' => $membershipStatusIndex
30705                ),
30706                array(
30707                    'PaymentReceivable.user_id' => $child->id,
30708                    'PaymentReceivable.status' => 0,
30709                    'PaymentReceivable.payment_element_type' => Configure::read('payment_element_type.reservation'),
30710                    'PaymentReceivable.created <=' => $dateTimeNow
30711                )
30712            );
30713        }
30714
30715        // appreciation receivable
30716        if ($appreciationReceivableAmount > 0) {
30717            $savePaymentArr = array(
30718                'user_id' => $child->id,
30719                'amount' => $appreciationReceivableAmount,
30720                'status' => 1,
30721                'type_id' => 1,
30722                'reference_id' => $child->id,
30723                'card_company' => $cardCompany,
30724                'param1' => json_encode($data),
30725                'form_type' => Configure::read('payment_credit_appreciation_receivable'),
30726                'ordd' => $paymentHash,
30727                'transaction_code' => $paymentHash,
30728                'currency_id' => $currencyId,
30729                'currency_code' => $currencyCode,
30730                'payment_id' => $paymentPlanId,
30731                'price_id' => $priceId,
30732                'payment_type' => $paymentType
30733            );
30734
30735            // create new payment for appreciation receivable
30736            $this->Payment->clear();
30737            $this->Payment->create();
30738            $this->Payment->set($savePaymentArr);
30739            if (!$this->Payment->save()) {
30740                $this->log(__METHOD__ . ' Failed to save payment data for appreciation receivable.' . json_encode($savePaymentArr), $this->logFileName);
30741                $dataSource->rollback();
30742                return;
30743            }
30744
30745            // set payment_id
30746            $arPaymentID = $this->Payment->id;
30747
30748            //update/add user`s settlement amount
30749            $this->User->updateUserPayments($savePaymentArr);
30750
30751            // set payment receivable statuses to 2 - received
30752            $this->PaymentReceivable->updateReceivableReservationPayment(
30753                $child->id,
30754                array(
30755                    'status' => 2,
30756                    'payment_id' => $arPaymentID,
30757                    'payment_collection_date' => $dateTimeNow,
30758                    'card_company' => $cardCompany,
30759                    'payment_plan_id' => $paymentPlanId,
30760                    'membership_type_index' => $membershipStatusIndex
30761                ),
30762                array(
30763                    'PaymentReceivable.user_id' => $child->id,
30764                    'PaymentReceivable.status' => 0,
30765                    'PaymentReceivable.payment_element_type' => Configure::read('payment_element_type.appreciation'),
30766                    'PaymentReceivable.created <=' => $dateTimeNow
30767                )
30768            );
30769        }
30770
30771        // live receivable
30772        if ($liveReceivableAmount > 0) {
30773            $savePaymentArr = array(
30774                'user_id' => $child->id,
30775                'amount' => $liveReceivableAmount,
30776                'status' => 1,
30777                'type_id' => 1,
30778                'reference_id' => $child->id,
30779                'card_company' => $cardCompany,
30780                'param1' => json_encode($data),
30781                'form_type' => Configure::read('payment_live_lesson_receivable'),
30782                'ordd' => $paymentHash,
30783                'transaction_code' => $paymentHash,
30784                'currency_id' => $currencyId,
30785                'currency_code' => $currencyCode,
30786                'payment_id' => $paymentPlanId,
30787                'price_id' => $priceId,
30788                'payment_type' => $paymentType
30789            );
30790
30791            // create new payment for live receivable
30792            $this->Payment->clear();
30793            $this->Payment->create();
30794            $this->Payment->set($savePaymentArr);
30795            if (!$this->Payment->save()) {
30796                $this->log(__METHOD__ . ' Failed to save payment data for live receivable.' . json_encode($savePaymentArr), $this->logFileName);
30797                $dataSource->rollback();
30798                return;
30799            }
30800
30801            // set payment_id
30802            $lrPaymentID = $this->Payment->id;
30803
30804            //update/add user`s settlement amount
30805            $this->User->updateUserPayments($savePaymentArr);
30806
30807            // set payment receivable statuses to 2 - received
30808            $this->PaymentReceivable->updateReceivableReservationPayment(
30809                $child->id,
30810                array(
30811                    'status' => 2,
30812                    'payment_id' => $lrPaymentID,
30813                    'payment_collection_date' => $dateTimeNow,
30814                    'card_company' => $cardCompany,
30815                    'payment_plan_id' => $paymentPlanId,
30816                    'membership_type_index' => $membershipStatusIndex
30817                ),
30818                array(
30819                    'PaymentReceivable.user_id' => $child->id,
30820                    'PaymentReceivable.status' => 0,
30821                    'PaymentReceivable.payment_element_type' => Configure::read('payment_element_type.live'),
30822                    'PaymentReceivable.created <=' => $dateTimeNow
30823                )
30824            );
30825        }
30826
30827        $dataSource->commit();
30828        $fields = array('status' => 1);
30829        if (isset($checkRes)) {
30830            $fields['response_text'] = array('aftee' => $checkRes);
30831        }
30832
30833        // update payment transaction
30834        $this->PaymentTransaction->updateWPPaymentTransaction(array('id' => $ptId, 'fields' => $fields));
30835
30836        return 'success_order';
30837    }
30838    /**
30839     * @api {get} /mobapp/payment/credit_retry_complete/:token mobapp_credit_retry_complete()
30840     * @apiName mobapp_credit_retry_complete
30841     * @apiGroup Payment
30842     * @apiDescription This endpoint is used to complete the credit card retry process.
30843     * 
30844     * @apiParam {String} token User token.
30845     * 
30846     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/close
30847     * 
30848     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if user token / user does not exist.
30849     * 
30850     * @apiSuccessExample Success Response:
30851     * Redirects to {{ENV}}/mobapp/close
30852     * 
30853     * @apiErrorExample Error Response:
30854     * Redirects to {{ENV}}/mobapp/retrypage
30855     * 
30856     * @apiSampleRequest off 
30857     */
30858    public function mobapp_credit_retry_complete(){
30859        $apiToken = !empty($this->request->query['token']) ? $this->request->query['token'] : null;
30860        //- validate user token
30861        if (!$apiToken) {
30862            $this->log(__METHOD__ . ' User token does not exist. ' . json_encode($userParams), 'card_retry');
30863            return myTools::getUrl() . '/mobapp/retrypage' . myTools::getMobappToken($_GET);            
30864        }
30865
30866        $userData = $this->User->getUserDataByApiToken($apiToken);
30867        //- validate user data
30868        if (!$userData) {
30869            $this->log(__METHOD__ . ' User does not exist. ' . json_encode($userParams), 'card_retry');
30870            return myTools::getUrl() . '/mobapp/retrypage' . myTools::getMobappToken($_GET);
30871        }
30872        
30873        $userData = $userData['User'];
30874
30875        // ~ process child receivable
30876        $childsDetail = $this->User->getChildsDetail($userData['id']);
30877
30878        if (!empty($childsDetail)) {
30879            foreach ($childsDetail as $detail) {
30880                $this->processChildReceivablePayment($detail['User'], $userData);
30881            }
30882        }
30883
30884        return $this->redirect(myTools::getUrl() . '/mobapp/close'.  myTools::getMobappToken($_GET));
30885    }
30886
30887    private function setLitePaymentInfoView($user = array(),$pcFlg = false,$isFreeOrTempUser = false,$compPageAllow = null){
30888
30889        if (!$user) {
30890            return false;
30891        }
30892
30893        // - init var 
30894        $currencyCode = $user['currency_code'];
30895
30896        $litePlanDataDisplay = array(
30897            'amount' => 0,
30898            'amountConstTaxDeducted' => 0,
30899            'priceId' => null
30900        );
30901
30902        $priceId = null;
30903
30904        $checkLitePlanSupported = $this->checkLitePlanSupported($user,$pcFlg,$compPageAllow);
30905
30906        if (isset($checkLitePlanSupported['enableLitePlan']) && $checkLitePlanSupported['enableLitePlan']) {
30907            // fetch light plan description
30908            $litePlanDataDisplay = $this->PaymentPlanPrice->getPaymentData(array(
30909                'currencyCode' => $currencyCode,
30910                'paymentPlanId' => Configure::read('payment_plans.light_plan'),
30911                'logFileName' => 'card_reregister'
30912            ));
30913
30914            // - set price id 
30915            $priceId = $litePlanDataDisplay['priceId'];
30916
30917            // - set price id for lite plan free
30918            if ($isFreeOrTempUser) {
30919                # get lite free data 
30920                $freeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
30921                    'currencyCode' => $user['currency_code'],
30922                    'paymentPlanId' => Configure::read('payment_plans.light_plan_free'),
30923                    'logFileName' => 'card_reregister'
30924                ));
30925
30926                $priceId = $freeTrialData['priceId'];
30927            }
30928
30929            // - set price id 
30930            $litePlanDataDisplay['priceId'] = $priceId;
30931        }
30932
30933        // - check if enabled lite plan 
30934        $enableLitePlan = isset($checkLitePlanSupported['enableLitePlan']) ? $checkLitePlanSupported['enableLitePlan'] : 0;
30935    
30936        $this->set('liteMonthlyPrice', myTools::formatAmount($litePlanDataDisplay['amount']));
30937        $this->set('litePlanAmount',$litePlanDataDisplay['amount']);
30938        $this->set('liteMonthylyPriceNoTax', myTools::formatAmount($litePlanDataDisplay['amountConstTaxDeducted']));
30939        $this->set('liteMonthylyPriceID', $priceId); //lite plan free price id
30940        $this->set('enableLitePlan',$enableLitePlan);
30941    }
30942
30943    public function liteUserAddCoinRewardForReenroll($user = array()){
30944        $this->autoRender = false;
30945
30946        $id = isset($user['id']) ? $user['id'] : null;
30947
30948
30949        if (!$id) {
30950            return false;
30951        }
30952
30953    
30954        // - fetch users mc coins
30955        $_monthlyPoints = $this->UsersPoint->getCurrentUserMCPoint($id); //  mc coins
30956
30957        // - fetch user current memo
30958        $updateMemo ="";
30959        $this->User->clear();
30960        $currentuser = $this->User->find('first',array(
30961            'conditions' => array(
30962                'User.id' => $id
30963            ),
30964            'recursive' => -1
30965        ));
30966        $currentUserMemo = $currentuser['User']['memo'];
30967        $dateNow = date('Y-m-d H:i:s');
30968
30969        // - confiscating mc coin
30970        if ((int) $_monthlyPoints > 0) {
30971            $_confiscateParams = array(
30972                'userId' => $id,
30973                'point' => $_monthlyPoints,
30974                'kbn' => 18, // Administrator Change/Minus
30975                'coinType' => 3
30976            );
30977
30978            $confiscate = $this->UsersPoint->confiscateUserLitePoints($_confiscateParams);
30979        
30980            if ($confiscate) {
30981                $updateMemo = $updateMemo . "\n {$dateNow} (Previous Coins (MC)【Confiscated】 : {$_monthlyPoints}. )";
30982            }
30983        }
30984
30985        $_doneConfiscatePoints = ClassRegistry::init('UsersPointHistory')->confiscateUserLitePointsCoinBox($id);
30986
30987    
30988        $nextChargeDate = $this->User->getNextChargeDate();
30989
30990        // - set to add monthly coin
30991        $_pointParams = array(
30992            'userId' => $id,
30993            'point' => Configure::read('lite_plan_monthly_coin'),
30994            'kbn' => Configure::read('lite_plan_bonus_kbn'), // 
30995            'kbnType' => 1, // add coin
30996            'coinType' => 3, // mc coin
30997            'dateExpiration' => $nextChargeDate,
30998            'coinFailMessage' => Configure::read('coin.failed.membership')
30999        );
31000
31001    
31002        // add user's points 
31003        $givebonus = $this->UsersPoint->performPointTransaction($_pointParams);
31004
31005    
31006        if ($givebonus) {
31007            $_coins = Configure::read('lite_plan_monthly_coin');
31008            $updateMemo = $updateMemo . "\n {$dateNow} Light Plan Bonus Coins (MC): {$_coins}";
31009        }
31010
31011        if (!empty($updateMemo)) {
31012            $updateMemo = $updateMemo . "\n" . $currentUserMemo;
31013            // - update user memo
31014            $this->User->clear();
31015            $this->User->set( array('id' => $id,'memo' => $updateMemo));
31016            $this->User->save();
31017        }
31018        
31019    }
31020
31021    public function processChangePlan(){
31022        $this->autoRender = false;
31023        $this->layout = false;
31024
31025        $this->response->disableCache();
31026
31027        $result = false;
31028        $error = true;
31029
31030        if ($this->request->is('post')) {
31031            $data = $this->request->data;
31032            $userID = $data['user_id'];
31033            $formType = $data['form_type'];
31034
31035            if (UserTable::checkPayingUser($userID)) {
31036                return json_encode(array('error' => true));
31037            }
31038
31039            // - if already has memcache on process 
31040            $checkProcess = $this->memcache->get('process_change_plan_'.$userID);
31041
31042            if ($checkProcess) {
31043                $this->memcache->delete('process_change_plan_'.$userID);
31044                return json_encode(array('hard_refresh' => true));
31045            }
31046
31047            $this->memcache->set(array(
31048                'key' => 'process_change_plan_'.$userID,
31049                'value' => $userID,
31050                'expire' => 3600 // 1 hour
31051            ));
31052
31053            if (!$userID || !$formType || !isset($data['payment_plan_type'])) {
31054                return json_encode(array('error' => true));
31055            }
31056
31057            // -- check if user exist 
31058            $user = $this->User->find('first',array(
31059                'conditions' => array(
31060                    'User.id' => $userID
31061                ),
31062                'recursive' => -1
31063            ));
31064
31065            if (!$user) {
31066                return json_encode(array('error' => true));
31067            }
31068
31069            // - validate user plan
31070            if(
31071                isset($user['User']['payment_plan_id']) && 
31072                $user['User']['payment_plan_id'] == 1 &&
31073                $data['payment_plan_type'] == 0 // selected plan type
31074            ) {
31075                return json_encode(array('error' => true));
31076            }
31077
31078            $user = $user['User'];
31079            $planID = $plan_before  = $user['payment_plan_id'];
31080            $paymentPlanType = $data['payment_plan_type'];
31081            $isFreeTrialNot = ($planID == Configure::read('payment_plans.free_trial')) ? true : false;
31082            $isLiteplanFree = ($planID == Configure::read('payment_plans.light_plan_free')) ? true : false;
31083            $plan_after = "";
31084
31085            $removeAllHeldCoins = false;
31086            $removeAllHeldCoupon = false;
31087            $offUnlimitedOptionNative = false;
31088            $offUnlimitedOptionCallan = false;
31089            $giveLiteMonthlyCoin = false;
31090            $removeLiteBonusCoin = true;
31091            $amount = 0;
31092
31093            $isPlanDownGrade = false;
31094            $planFormType = Configure::read('payment_lite_plan_upgrade');
31095
31096            $membershipTypes = UserTable::getEngMembershipTypeData();
31097            $userObject = new UserTable($user);
31098
31099            $membershipTypeIndex = $userObject->getMembershipTypeIndex();
31100            $statusBefore = $membershipTypes[$membershipTypeIndex];
31101            $statusAfter = $membershipTypes[1];
31102
31103            $totalPayment = 0;
31104            $chargePaymentFlg = false;
31105            
31106        
31107            // - check if from free trial user not yet conducted and change the plan to lite plan
31108            if ($isFreeTrialNot && (int) $paymentPlanType == 1) {
31109                $removeAllHeldCoins = true;
31110                $removeAllHeldCoupon = true;
31111                $offUnlimitedOptionNative = true;
31112                $offUnlimitedOptionCallan = true;
31113                $giveLiteMonthlyCoin = true;
31114
31115                // - set the lite plan id to paid
31116                $planID = $plan_after = Configure::read('payment_plans.light_plan');
31117                $planFormType = Configure::read('payment_lite_plan_downgrade');
31118
31119                // - set status after 
31120                $_mt = Configure::read('membership_type_lightplan_paid');
31121                $statusAfter = $membershipTypes[$_mt];
31122
31123                $chargePaymentFlg = true;
31124            }
31125
31126            // - changes from ligth plan free to (premium plan paid or premium plan paid with annual discount option)
31127            if ($isLiteplanFree && (int) ($paymentPlanType == 0 || $paymentPlanType == 2)) {
31128
31129                // - set premium plan id 
31130                $planID = $plan_after = Configure::read('payment_plans.premium_plan');
31131                $planFormType = Configure::read('payment_lite_plan_upgrade');
31132
31133                // - set status after to premium plan (paid)
31134                $_mt = Configure::read('membership_type_premiumplan_paid');
31135                $statusAfter = $membershipTypes[$_mt];
31136
31137                $chargePaymentFlg = true;
31138            }
31139
31140            // - changes plan from premium plan (paid) -> light plan (paid)
31141            if (!$isFreeTrialNot && (int) $paymentPlanType == 1) {
31142                $chargePaymentFlg = true;
31143
31144                $removeAllHeldCoins = true;
31145                $removeAllHeldCoupon = true;
31146                $offUnlimitedOptionNative = true;
31147                $offUnlimitedOptionCallan = true;
31148                $giveLiteMonthlyCoin = true;
31149
31150                // - set the lite plan id to paid
31151                $planID = $plan_after = Configure::read('payment_plans.light_plan');
31152                $planFormType = Configure::read('payment_lite_plan_downgrade');
31153
31154                // - set status after 
31155                $_mt = Configure::read('membership_type_lightplan_paid');
31156                $statusAfter = $membershipTypes[$_mt];
31157
31158                $chargePaymentFlg = true;
31159            }
31160
31161            // - changes the plan from light plan (paid) -> (premium plan paid (paid) or premium plan paid with annual discount option)
31162            if (!$isLiteplanFree && (int) ($paymentPlanType == 0 || $paymentPlanType == 2)) {
31163                $removeAllHeldCoins = true;
31164                $removeAllHeldCoupon = true;
31165                $chargePaymentFlg = true;
31166
31167                $offUnlimitedOptionNative = true;
31168                $offUnlimitedOptionCallan = true;
31169
31170                // - set premium plan id 
31171                $planID = $plan_after = Configure::read('payment_plans.premium_plan');
31172                $planFormType = Configure::read('payment_lite_plan_upgrade');
31173
31174                // - set status after to premium plan (paid)
31175                $_mt = Configure::read('membership_type_premiumplan_paid');
31176                $statusAfter = $membershipTypes[$_mt];
31177            }
31178
31179            //- NJ-27262 Chocotto Camp(Paid)
31180            if ($paymentPlanType == Configure::read('register_plan_types.chocotto')) {
31181                $removeAllHeldCoins = true;
31182                $chargePaymentFlg = true;
31183
31184                $offUnlimitedOptionNative = true;
31185                $offUnlimitedOptionCallan = true;
31186
31187                // - set chocotto plan id 
31188                $planID = $plan_after = Configure::read('payment_plans.chocotto_plan');
31189                $planFormType = Configure::read('payment_credit_chocotto_monthly_payment');
31190
31191                // - set status after to chocotto plan (paid)
31192                $_mt = Configure::read('membership_type_chocotto_plan_paid');
31193                $statusAfter = $membershipTypes[Configure::read('membership_type_chocotto_plan_paid')];
31194                //NJ-33743
31195                $memcached = new myMemcached();
31196                $memcached->set(array(
31197                    'key'    => 'user_plan_change_premium_to_chocotto',
31198                    'value'  => true,
31199                    'expire' => 120
31200                ));
31201            }
31202
31203            $plan = $this->PaymentPlanPrice->getPaymentData(array(
31204                'currencyCode' => $user['currency_code'],
31205                'paymentPlanId' => $planID,
31206                'logFileName' => 'card_reregister'
31207            ));
31208
31209            #processPayPalPayment
31210            if (!$plan) {
31211                return json_encode(array('error' => true));
31212            }
31213
31214            // - validate to double check if the plan that the user want's
31215            if ((int) $planID == (int) $plan_before) {
31216                # check if user is already changed into plan
31217                return json_encode(array('hard_refresh' => true));
31218            }
31219
31220            $removeAllHeldCoins = true; // override to remove all mc coins
31221
31222            $paramsData = array(
31223                'removeAllHeldCoins' => $removeAllHeldCoins,
31224                'removeAllHeldCoupon' => $removeAllHeldCoupon,
31225                'offUnlimitedOptionNative' => $offUnlimitedOptionNative,
31226                'offUnlimitedOptionCallan' => $offUnlimitedOptionCallan,
31227                'giveLiteMonthlyCoin' => $giveLiteMonthlyCoin,
31228                'amount' => $amount,
31229                'paymentPlanData' => $plan,
31230                'formType' => $planFormType,
31231                'statusAfter' => $statusAfter,
31232                'statusBefore' => $statusBefore,
31233                'removeLiteBonusCoin' => $removeLiteBonusCoin,
31234                'totalPayment' => $totalPayment
31235            );
31236
31237            if ($chargePaymentFlg) {
31238                $totalPayment  = $plan['amount'];
31239                
31240                // get reserve payment receivable
31241                $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userID);
31242
31243                // get live lesson payment receivable
31244                $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userID, false, Configure::read('appreciation_data.payment_element_type'));
31245
31246                // get live lesson payment receivable
31247                $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userID, false, Configure::read('payment_element_type.live'));
31248
31249                // - native option payment ??
31250                $totalPayment =  $totalPayment + $receivablePayment + $appreciationReceivable + $liveLessonReceivable; 
31251
31252                if ($paymentPlanType == 2) {
31253                    // get active annual discount option
31254                    $annualDiscountOptionData = $this->DiscountOptionsPrice->getPaymentData(['currencyCode' => $user['currency_code'], 'discountOptionId' => Configure::read('discount_option.annual.plan_id')]);
31255
31256                    if (!$annualDiscountOptionData) {
31257                        return json_encode(array('hard_refresh' => true));
31258                    }
31259
31260                    $annualDiscountOptionData += [
31261                        'dosh_event' => Configure::read('discount_option.dosh_event.annual_discount'),
31262                        'dosh_status' => Configure::read('discount_option.dosh_status.monthly_discount')
31263                    ];
31264
31265                    $paramsData['discountOption'] = $annualDiscountOptionData;
31266                    $totalPayment = $totalPayment - $annualDiscountOptionData['amount'];
31267                }
31268
31269                $paramsData['totalPayment'] = $totalPayment;// - set to charge
31270
31271            }
31272
31273            $paramsData['charge_payment_flg'] = $chargePaymentFlg;
31274            $paramsData['raw_monthly_amount'] = $plan['amount'];
31275    
31276            // - if paypal user 
31277            if ((int) $user['card_company'] == Configure::read('card_company.paypal')) {
31278                $result = $this->paypal_payment_change_plan_process($paramsData,$user);
31279                $this->log(__METHOD__ . ' here on starting the paypal process paramsData | '.json_encode($paramsData), 'paypal_debug');
31280            }
31281
31282            if ((int) $user['card_company'] == Configure::read('card_company.zeus')) {
31283                $result = $this->zeus_payment_change_plan($paramsData,$user);
31284            }
31285
31286            $error = ($result['success']) ? false : true;
31287
31288            // - update ? 
31289            if ($result) {
31290                $this->User->clear();
31291                $read = $this->User->read(array('id','payment_plan_id','price_id'),$userID);
31292
31293                if ($read) {
31294                    $this->sharedUserData['User']['payment_plan_id'] = $read['User']['payment_plan_id'];
31295                    $this->sharedUserData['User']['price_id'] = $read['User']['price_id'];
31296                }
31297
31298                $membership = $userObject->getMembershipTypeIndex();
31299                if (in_array($membership, Configure::read('allow_coupon.membership_type_free'))) {
31300                    $ruData = array(
31301                        'referee_id' => $userID,
31302                        'payment_plan_id' => Configure::read('payment_plans.premium_plan'),
31303                        'currency_code' => $user['currency_code'],
31304                        'form_type' => Configure::read('payment_credit_authentication'),
31305                        'logFileName' => 'card_reregister'
31306                    );
31307
31308                    $couponReferredData = $this->UsersReferral->checkReferredUser($ruData);
31309                    if (isset($couponReferredData['error']) && $couponReferredData['error']) {
31310                        $this->log(__METHOD__ . ' Failed to update users referral event flg.' . json_encode($ruData), 'card_reregister');
31311                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userID, 'Failed to update users referral event flg.', $ruData);
31312                    }
31313                }
31314
31315
31316                if (in_array($membership, Configure::read('allow_coupon.membership_type'))) {
31317                    $params = array(
31318                        'userId' => $userID,
31319                        'action_type' => 1 // confiscate only the used status 
31320                    );
31321                    if (!$this->UsersCouponV1->confiscateAllCoupon($params)) {
31322                        $this->log(__METHOD__ . ' Failed to conficate change plan.' . json_encode($userID), 'card_reregister');
31323                    }
31324                }
31325            }
31326
31327            if (
31328                isset($result['success']) && 
31329                $result['success'] &&
31330                $this->User->isParent($userID) // - check if parent user
31331            ) {
31332                $this->processChildWithdrawal($user);
31333            }
31334
31335            // delete memcache
31336            if ($this->memcache->get('process_change_plan_'.$userID)) {
31337                $this->memcache->delete('process_change_plan_'.$userID);
31338            }
31339
31340            //- logout user chocotto plan
31341            if (
31342                isset($result['success']) && 
31343                $result['success'] &&                
31344                $paymentPlanType == Configure::read('register_plan_types.chocotto')
31345            ) {
31346
31347                //- add default daily lesson time, if no data yet on
31348                $this->UsersDetail->chocottoCampUserDetails($userID, true);
31349                $this->Auth->logout();
31350            }
31351
31352            return json_encode(array(
31353                'success' => $result['success'],
31354                'error' => $error,
31355                'paymentHash' => $result['paymentHash']
31356            ));
31357        }
31358
31359        return json_encode(array(
31360            'success' => $result['success'],
31361            'error' => $error,
31362            'paymentHash' => $result['paymentHash']
31363        ));
31364    }
31365
31366    private function processChildWithdrawal($userData = array()) {
31367
31368        if(!isset($userData['id']) || !$userData['id']) {
31369            return false;
31370        }
31371
31372        $user = new UserTable($userData);
31373        $user_id = $user->id;
31374
31375        $childData = array();
31376        $wd = date('Y/m/d H:i:s');
31377
31378        // - get children data
31379        $childsDetail = $this->User->getChildsDetail($user_id);
31380
31381        $lastModifiedDate = date('YmdHis');
31382
31383        $childDataUpdateNativeOption = array();
31384        $childDataUpdateCallanOption = array();
31385
31386        // - check children data if any
31387        if (!empty($childsDetail)) {
31388
31389            $saveLogParams['doubleCheckFlg'] = 2; // unsubscribed
31390
31391            foreach ($childsDetail as $detail) {
31392
31393                // - db object
31394                $db = ConnectionManager::getDataSource('default');
31395                if ($db->isConnected()) {
31396                    $db->close(); // stop
31397                }
31398                $db->reconnect();
31399
31400                // - update child memo
31401                $childMemo = $wd.' system-pc 退会 : parent ['. $user_id .'] change plan' ."\n".$detail['User']['memo'];
31402
31403                //default 
31404                $childNativeOptionParams = array();
31405
31406                $childUpdateParam = array(
31407                        'id' => $detail['User']['id'],
31408                        'deactivation_time' => $lastModifiedDate,
31409                        'fail_flg' => 0,
31410                        'charge_flg' => 0,
31411                        'double_check_flg' => 2,
31412                        'native_option' => 0,
31413                        'callan_option' => 0,
31414                        'memo' => $childMemo,
31415                        'parent_id' => NULL, 
31416                        'next_charge_date' => NULL, 
31417                        'monthly_payment' => null, 
31418                        'price_id' => null,
31419                        'payment_plan_id' => null,
31420                        'card_token' => null,
31421                        'card_company' => null,
31422                        'expired_card_flg' => 0,
31423                        'card_expiration_date' => null,
31424                        'card_number' => null,
31425                        'card_brand' => null,
31426                        'aftee_transaction_identifier' => null,
31427                        'wp_transaction_identifier' => null,
31428                        'google_cloud_id' => null
31429                );
31430
31431                if ($userData['card_company'] == Configure::read('card_company.aftee')) {
31432                    $childUpdateParam['card_company'] = NULL;
31433                    $childUpdateParam['card_brand'] = 'AFTEE2';
31434                }
31435
31436                // - check if has native option
31437                if (isset($detail['User']['native_option']) && $detail['User']['native_option']) {
31438
31439                        $childNativeOptionParams = array(
31440                            'id' => $detail['User']['id'],
31441                            'native_option_cancellation_time' => date("Y-m-d H:i:s")
31442                        );
31443
31444                        $childDataUpdateNativeOption[] = array('User' => $childNativeOptionParams);
31445                }
31446
31447                // - check if has callan option
31448                if (isset($detail['User']['callan_option']) && $detail['User']['callan_option']) {
31449                        $childCallanOptionParams = array(
31450                            'id' => $detail['User']['id'],
31451                            'callan_option_cancellation_time' => date("Y-m-d H:i:s")
31452                        );
31453
31454                        $childDataUpdateCallanOption[] = array('User' => $childCallanOptionParams);
31455                }
31456
31457                // - set update data from each child
31458                $childData[] = array('User' => $childUpdateParam);
31459
31460                // - add deactivation log
31461                $this->loadModel('FamilyDeactivationLog');
31462                $this->FamilyDeactivationLog->addLog($detail['User']['id']);
31463
31464                // - disable child's reserved lessons
31465                $this->LessonSchedule->deactivateDisableReservedLessons($detail['User']['id'], true);
31466
31467                // save child change membership status
31468                $saveLogParams['userData'] = $detail;
31469                UserStatusChangeLogTable::saveLogUnsubscribeUser($saveLogParams);
31470                
31471                $switchAccountParams = array(
31472                    'parentId' => $user_id,
31473                    'userId' => $detail['User']['id']
31474                );
31475
31476                // - delete switch account data for child
31477                $this->UsersFamilyAccount->removeSwitchAccount($switchAccountParams);
31478
31479                // - add deactivation lock
31480                $user->saveUserDeactivationLock($detail['User']['id']);
31481
31482            }
31483
31484            $this->User->saveMany($childData);
31485
31486            if (isset($childDataUpdateNativeOption) && $childDataUpdateNativeOption) {
31487                // - update the native option
31488                $this->User->saveMany($childDataUpdateNativeOption);
31489            }
31490
31491            if (isset($childDataUpdateCallanOption) && $childDataUpdateCallanOption) {
31492                // - update the callan option
31493                $this->User->saveMany($childDataUpdateCallanOption);
31494            }
31495
31496            // - delete from family plan list
31497            $this->FamilyPlanList->deleteAll(array('FamilyPlanList.parent_id' => $user_id));
31498
31499            return true;
31500        }
31501    }
31502
31503    private function paypal_payment_change_plan_process($data = array(),$user = array()){
31504
31505        $logFileName = 'paypal_debug';
31506
31507        // load PayPal class
31508        if (!class_exists('PayPal')) {
31509            App::import('Lib', 'PayPal');
31510        }
31511
31512        $paypal = new PayPal();
31513
31514        $result = ['success' => false, 'paymentHash' => null];
31515
31516        // get access token data
31517        $accessTokenData = $paypal->getAccessToken();
31518
31519        if (!isset($accessTokenData['access_token'])) {
31520            $this->log(__METHOD__ . " Error. --> " . json_encode($accessTokenData), $logFileName);
31521            return $result;
31522        }
31523
31524        // - set access token data
31525        $accessToken = $accessTokenData['access_token'];
31526
31527        if (!$user || !$data) {
31528            $this->log(__METHOD__ . ' Missing billing agreement param(s). --> ' . json_encode($user), $logFileName);
31529            return $result;
31530        }
31531
31532        $formType = $data['formType'] ?? null;
31533
31534        if (!$formType) {
31535            $this->log(__METHOD__ . ' Missing form type param(s). --> ' . json_encode($data), $logFileName);
31536            return $result;
31537        }
31538
31539        if (!$data['statusAfter']) {
31540            $this->log(__METHOD__ . ' Missing statusAfter param(s). --> ' . json_encode($data), $logFileName);
31541            return $result;
31542        }
31543
31544        if (!isset($data['charge_payment_flg'])) {
31545            $this->log(__METHOD__ . ' Missing charge_payment_flg param(s). --> ' . json_encode($data), $logFileName);
31546            return $result;
31547        }
31548
31549        // - set total amount 
31550        $totalPayment = $nativeOptionPayment = $callanOptionPayment = $discountedAmount = 0;
31551
31552        $totalPayment = $data['totalPayment'] ?? 0;
31553        $monthlyPayment = $data['raw_monthly_amount'] ?? 0;
31554
31555        // - update user for creating payment transaction
31556        $user['payment_plan_id'] = $paymentPlanId = $data['paymentPlanData']['paymentPlanId'];
31557        $user['price_id'] = $priceId = $data['paymentPlanData']['priceId'];
31558        $user['paymentAmount'] = $totalPayment;
31559
31560        $paymentType = Configure::read('payment_types.payment_plan');
31561        $cardCompany = Configure::read('card_company.paypal');
31562
31563        $familyId = null;
31564        $billingAgreementId = $user['paypal_billing_agreement_id'];
31565        $platform = $user['platform'];
31566
31567        $statusBefore = $data['statusBefore'];
31568        $userId = $user['id'];
31569        $sendId = $userId;
31570
31571        $paymentParams = array(
31572            'currencyCode' => $user['currency_code'],
31573            'formType' => $formType,
31574            'paymentType' => $paymentType,
31575            'logFileName' => $logFileName,
31576            'paymentAmount' => $totalPayment,
31577            'familyId' => $familyId,
31578            'priceId' => $priceId,
31579            'paymentPlanId' => $paymentPlanId,
31580            'nativeOptionPayment' => $nativeOptionPayment,
31581            'callanOptionPayment' => $callanOptionPayment,
31582            'statusBefore' => $statusBefore,
31583            'statusAfter' => $data['statusAfter'],
31584            'platform' => $platform
31585        );
31586
31587        if (isset($data['discountOption'])) {
31588            $paymentParams['discountOption'] = $data['discountOption'];
31589            $monthlyPayment -= $data['discountOption']['amount'];
31590            $paymentParams['discountOption'] += [
31591                'dosh_type' => Configure::read('discount_option.dosh_type.plan_change'),
31592                'dosh_status' => Configure::read('discount_option.dosh_status.subscription'),
31593                'option_after_name' => 'Annual Discount Option',
31594                'option_type' => 3
31595            ];
31596        }
31597
31598        $paymentHash = myTools::generateOrderCode($userId);
31599        $result['paymentHash'] = $paymentHash;
31600
31601        $ptParams = array(
31602            'user_id' => $userId,
31603            'payment_hash' => $paymentHash,
31604            'payment_params' => json_encode($paymentParams),
31605            'course_id' => Configure::read("credit.course_id")
31606        );
31607
31608        // create payment transaction
31609        if (!$pt = $this->PaymentTransaction->setWPPaymentTransaction($ptParams)) {
31610            $this->log(__METHOD__ . ' Failed to create payment transaction. --> ' . json_encode($ptParams), $logFileName);
31611            return $result;
31612        }
31613
31614        // set transaction
31615        $dataSource = $this->User->getDataSource();
31616        $dataSource->begin();
31617
31618        $dateNow = date('Y-m-d H:i:s');
31619        $mpptId = $pt['id']; // transaction id
31620        $currencyId = Configure::read('default.settlement_currency_id'); // set currency id to jpy
31621        $currencyCode = $user['currency_code'];
31622
31623        $paymentHash = $pt['payment_hash'];
31624        $ptPassword = $pt['password'];
31625
31626        $createOrderParams = array(
31627            'accessToken' => $accessToken,
31628            'paypalRequestId' => $pt['id'],
31629            'intent' => 'CAPTURE',
31630            'paymentHash' => $paymentHash,
31631            'userId' => $sendId,
31632            'currencyCode' => $currencyCode,
31633            'amount' => (int)$totalPayment,
31634            'billingAgreementId' => $billingAgreementId
31635        );
31636
31637        $paypalData = $createOrderParams;
31638        $this->log(__METHOD__ . ' totalPayment | '.json_encode($totalPayment), 'paypal_debug');
31639
31640        // - if from free trial
31641        if ($totalPayment == 0) {
31642            $createOrderParams['amount'] = 1;
31643        }
31644
31645        // create order
31646        $createOrderResult = $paypal->createOrder($createOrderParams);
31647        $paypalData['create_order_data'] = $createOrderResult;
31648
31649        // save settlement history for tracking
31650        if (
31651            !SettlementHistoryTable::add(array(
31652                    'userId' => $userId,
31653                    'params' => json_encode($paypalData),
31654                    'createdIp' => $dateNow,
31655                    'modifiedIp' => $dateNow
31656                )
31657            ) 
31658        ) {
31659            $this->log(__METHOD__ . ' Failed to save paypal result data in settlement history. ' . json_encode($paypalData), $logFileName);
31660            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save paypal result data in settlement history', $paypalData);
31661            return $result;
31662        }
31663
31664        if (isset($createOrderResult['status']) && $createOrderResult['status'] === 'COMPLETED'){
31665
31666            $paymentData = array(
31667                'user_id' => $userId,
31668                'amount' => $monthlyPayment,
31669                'status' => 1,
31670                'reference_id' => $userId,
31671                'payment_transaction_password' => $ptPassword,
31672                'card_company' => $cardCompany,
31673                'param1' => json_encode($paypalData),
31674                'form_type' => $formType,
31675                'ordd' => $paymentHash,
31676                'transaction_code' => $paymentHash,
31677                'currency_id' => $currencyId,
31678                'currency_code' => $currencyCode,
31679                'payment_id' => $paymentPlanId,
31680                'price_id' => $priceId,
31681                'payment_type' => $paymentType,
31682                'discounted_amount' => $discountedAmount
31683            );
31684
31685            // create new payment
31686            $this->Payment->clear();
31687            $this->Payment->create();
31688            $this->Payment->set($paymentData);
31689            $this->Payment->validate = array();
31690
31691            // check if payment was not saved
31692            if (!$this->Payment->save()) {
31693                $this->log(__METHOD__ . ' Failed to save payment data. ' . json_encode($paymentData) . ' -- ' . json_encode($data), $logFileName);
31694                return $result;
31695            }
31696
31697            // check if payment plan upgrade
31698            if ($formType == Configure::read('payment_lite_plan_upgrade')) {
31699                // get user zero student discount term
31700                $discountOptionTermData = $this->UserDiscountOptionsTerm->getTerm([
31701                    'user_id' =>  $userId,
31702                    'discount_option_id' => Configure::read('discount_option.zero_student.plan_id'),
31703                    'status' => 1
31704                ]);
31705
31706                // stop zero student discount
31707                if ($discountOptionTermData) {
31708                    // open tunnel
31709                    myTools::initializeApiTunnel(['DiscountOptionController']);
31710
31711                    // initialize controller
31712                    $doc = new DiscountOptionController(); 
31713
31714                    $docParams = [
31715                        'discountOptionId' => $discountOptionTermData['discount_option_id'],
31716                        'discountOptionPriceId' => $discountOptionTermData['discount_option_price_id'],
31717                        'termId' => $discountOptionTermData['discount_option_term_id'],
31718                        'cancellationFee' => 0,
31719                        'cancellationType' => Configure::read('discount_option.dosh_type.plan_change'),
31720                        'userData' => $user,
31721                        'fromController' => $this->request->params['controller'],
31722                        'fromAction' => $this->request->params['action'],
31723                        'doshStatus' => Configure::read('discount_option.dosh_status.midterm_cancellation')
31724                    ];
31725
31726                    // set data
31727                    $doc->params = $docParams;
31728
31729                    if (!$doc->stopDiscountOption()) {
31730                        $this->log(__METHOD__ . ' Failed to stop discount option. ' . json_encode($docParams) . ' -- ' . json_encode($data), $logFileName);
31731                        return $result;
31732                    }
31733                }
31734            }
31735
31736            $paymentId = $this->Payment->id;
31737            //update/add user`s settlement amount
31738            $this->User->updateUserPayments($paymentData);
31739
31740
31741            $baId = $billingAgreementId;
31742
31743            $saveUserArr = array(
31744                'id' => $userId,
31745                'status' => 1,
31746                'modified' => $dateNow,
31747                'fail_flg' => 0,
31748                'charge_flg' => 1,
31749                'counseling_attended_flg' => 0,
31750                'card_company' => $cardCompany,
31751                'hash16' => $userId,
31752                'payment_plan_id' => $paymentPlanId,
31753                'price_id' => $priceId,
31754                'corporate_id' => null,
31755                'corporate_type' => null,
31756                'last_charge_date' => $dateNow
31757            );
31758
31759            // - check charge flag to change the last and next charge date
31760            $chargeFlg = isset($data['charge_payment_flg']) ? (int) $data['charge_payment_flg'] : 0;
31761            $liteNxtChargeDate = null;
31762            if ($chargeFlg) {
31763            
31764                // - set next charge date 
31765                $nextChargeDate = $liteNxtChargeDate = $this->User->getNextChargeDate();
31766                $saveUserArr['next_charge_date'] = $nextChargeDate;
31767            }
31768
31769            // update the user information
31770            $this->User->validate = array();
31771            if (!$read = $this->User->read(array_keys($saveUserArr), $userId)) {
31772                $this->log(__METHOD__ . ' User id does not exist. ' . json_encode($userData) . ' -- ' . json_encode($createOrderResult), $logFileName);
31773                $dataSource->rollback();
31774                return $result;
31775            }
31776
31777            $this->User->set($saveUserArr);
31778            if (!$this->User->save()) {
31779                $this->log(__METHOD__ . ' Failed update user data. ' . json_encode($saveUserArr) . ' -- ' . json_encode($createOrderResult), $logFileName);
31780                $dataSource->rollback();
31781                return $result;
31782            }
31783
31784            // get reserve payment receivable
31785            $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userId);
31786
31787            // get live lesson payment receivable
31788            $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('appreciation_data.payment_element_type'));
31789
31790            // get live lesson payment receivable
31791            $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.live'));
31792
31793            $membershipStatusIndex = UserTable::getStudentMembershipStatus($userId);
31794
31795            $discountOption = isset($data['discountOption']) ? $data['discountOption'] : [];
31796            // create discount term if user change plan to premium with annual discount option
31797            if ($discountOption) {
31798                // set data for user discount option term
31799                $udotData = [
31800                    'userId' => $userId,
31801                    'discountOptionId' => $discountOption['discount_option_id'],
31802                    'discountOptionPriceId' => $discountOption['discount_option_price_id'],
31803                    'contractStart' => date('Y-m-d 00:00:00'),
31804                    'logFileName' => $logFileName,
31805                    'paymentId' => $paymentId,
31806                    'discountAmount' => $discountOption['amount'],
31807                    'doshEvent' => $discountOption['dosh_event'],
31808                    'currencyCode' => $currencyCode,
31809                    'doshStatus' => $discountOption['dosh_status'],
31810                    'formType' => $formType
31811                ];
31812
31813                // create user discount option term
31814                if (!$this->UserDiscountOptionsTerm->createTerm($udotData)) {
31815                    $this->log(__METHOD__ . ' Failed to create user discount option term. ' . json_encode($udotData) . ' -- ' . json_encode($createOrderResult), $logFileName);
31816                    $dataSource->rollback();
31817                    return $result;
31818                }
31819
31820                $adoLogParams = [
31821                    'user_id' => $userId,
31822                    'platform' => $platform,
31823                    'status' => 1, // subscribe
31824                    'controller_name' => $this->request->params['controller'],
31825                    'action_name' => $this->request->params['action'],
31826                    'user_type' => 0, // normal user
31827                    'option_before' => '',
31828                    'option_after' => 1,
31829                    'option_before_name' => '',
31830                    'option_after_name' => 'Annual Discount Option',
31831                    'option_type' => 3, // annual discount option
31832                    'payment_plan_id' => $paymentPlanId
31833                ];
31834
31835                if (!$this->UserOptionChangeLog->saveOptionChangeLog($adoLogParams)) {
31836                    $this->log(__METHOD__ . ' Failed to update option change. ' . json_encode($adoLogParams), $logFileName);
31837                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update option change. ', $adoLogParams);
31838                    $dataSource->rollback();
31839                    return $result;
31840                }
31841            }
31842
31843            // receivable
31844            if ($receivablePayment) {
31845            
31846                $paymentData = array(
31847                    'user_id' => $userId,
31848                    'amount' => $receivablePayment,
31849                    'status' => 1,
31850                    'type_id' => 1,
31851                    'reference_id' => $userId,
31852                    'card_company' => $cardCompany,
31853                    'param1' => json_encode($data),
31854                    'form_type' => Configure::read('payment_credit_receivable'),
31855                    'ordd' => $paymentHash,
31856                    'currency_code' => $currencyCode,
31857                    'transaction_code' => $paymentHash,
31858                    'price_id' => $priceId,
31859                    'payment_id' => $paymentPlanId,
31860                    'payment_type' => $paymentType,
31861                    'discounted_amount' => 0
31862                );
31863
31864                // create new payment
31865                $this->Payment->clear();
31866                $this->Payment->create();
31867                $this->Payment->set($paymentData);
31868                $this->Payment->validate = array();
31869
31870                if (!$this->Payment->save()) {
31871                    $this->log(__METHOD__ . ' Failed to save payment data for receivable.' . json_encode($paymentData), $logFileName);
31872                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data for receivable.', $paymentData);
31873                    $dataSource->rollback();
31874                    return $result;
31875                }
31876
31877                    //update/add user`s settlement amount
31878                $this->User->updateUserPayments($paymentData);
31879                // set payment_id
31880                $paymentIdn = $this->Payment->id;
31881                
31882                // set payment receivable statuses to 2 - received
31883                $this->PaymentReceivable->updateReceivableReservationPayment(
31884                    $userId,
31885                    array(
31886                        'status' => 2,
31887                        'payment_id' => $paymentIdn,
31888                        'payment_collection_date' => date("Y-m-d H:i:s"),
31889                        'card_company' => $cardCompany,
31890                        'payment_plan_id' => $paymentPlanId,
31891                        'membership_type_index' => $membershipStatusIndex
31892                    ),
31893                    array(
31894                        'PaymentReceivable.user_id' => $userId,
31895                        'PaymentReceivable.status' => 0,
31896                        'PaymentReceivable.payment_element_type' => 1,
31897                        'PaymentReceivable.created <=' => date("Y-m-d H:i:s")
31898                    )
31899                );
31900            }
31901
31902            if ($appreciationReceivable) {
31903                // set variables
31904                $paymentData = array(
31905                    'user_id' => $userId,
31906                    'amount' => $appreciationReceivable,
31907                    'status' => 1,
31908                    'type_id' => 1,
31909                    'reference_id' => $userId,
31910                    'card_company' => $cardCompany,
31911                    'param1' => json_encode($data),
31912                    'form_type' => Configure::read('appreciation_data.payment_form_type'),
31913                    'ordd' => $paymentHash,
31914                    'currency_code' => $currencyCode,
31915                    'transaction_code' => $paymentHash,
31916                    'price_id' => $priceId,
31917                    'payment_id' => $paymentPlanId,
31918                    'payment_type' => $paymentType,
31919                    'discounted_amount' => 0
31920                );
31921
31922                // create new payment
31923                $this->Payment->clear();
31924                $this->Payment->create();
31925                $this->Payment->set($paymentData);
31926                $this->Payment->validate = array();
31927
31928                    if (!$this->Payment->save()) {
31929                    $this->log(__METHOD__ . ' Failed to save appreciation receivable payment data for receivable.' . json_encode($paymentData), $logFileName);
31930                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data for receivable.', $paymentData);
31931                    $dataSource->rollback();
31932                    return $result;
31933                }
31934                //update/add user`s settlement amount
31935                $this->User->updateUserPayments($paymentData);
31936                // set payment_id
31937                $paymentIdn = $this->Payment->id;
31938
31939                $this->PaymentReceivable->updateReceivableReservationPayment(
31940                    $userId,
31941                    array(
31942                        'status' => 2,
31943                        'payment_id' => $paymentIdn,
31944                        'payment_collection_date' => date("Y-m-d H:i:s"),
31945                        'card_company' => $cardCompany,
31946                        'payment_plan_id' => $paymentPlanId,
31947                        'membership_type_index' => $membershipStatusIndex
31948                    ),
31949                    array(
31950                        'PaymentReceivable.user_id' => $userId,
31951                        'PaymentReceivable.status' => 0,
31952                        'PaymentReceivable.payment_element_type' => Configure::read('appreciation_data.payment_element_type'),
31953                        'PaymentReceivable.created <=' => date("Y-m-d H:i:s")
31954                    )
31955                );
31956            }
31957
31958            if ($liveLessonReceivable) {
31959                $paymentData = array(
31960                    'user_id' => $userId,
31961                    'amount' => $liveLessonReceivable,
31962                    'status' => 1,
31963                    'type_id' => 1,
31964                    'reference_id' => $userId,
31965                    'card_company' => $cardCompany,
31966                    'param1' => json_encode($data),
31967                    'form_type' => Configure::read('payment_live_lesson_receivable'),
31968                    'ordd' => $paymentHash,
31969                    'currency_code' => $currencyCode,
31970                    'transaction_code' => $paymentHash,
31971                    'price_id' => $priceId,
31972                    'payment_id' => $paymentPlanId,
31973                    'payment_type' => $paymentType,
31974                    'discounted_amount' => $discountedAmount
31975                );
31976
31977                // create new payment
31978                $this->Payment->clear();
31979                $this->Payment->create();
31980                $this->Payment->set($paymentData);
31981                $this->Payment->validate = array();
31982
31983                if (!$this->Payment->save()) {
31984                    $this->log(__METHOD__ . ' Failed to save payment data for receivable.' . json_encode($paymentData), $logFileName);
31985                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data for receivable.', $paymentData);
31986                    $dataSource->rollback();
31987                    return $result;
31988                }
31989
31990                //update/add user`s settlement amount
31991                $this->User->updateUserPayments($paymentData);
31992                // set payment_id
31993                $paymentIdn = $this->Payment->id;
31994
31995                // set live lesson payment receivable statuses to 2 - received
31996                $this->PaymentReceivable->updateReceivableReservationPayment(
31997                    $userId,
31998                    array(
31999                        'status' => 2,
32000                        'payment_id' => $paymentIdn,
32001                        'payment_collection_date' => date("Y-m-d H:i:s"),
32002                        'card_company' => $cardCompany,
32003                        'payment_plan_id' => $paymentPlanId,
32004                        'membership_type_index' => $membershipStatusIndex
32005                    ),
32006                    array(
32007                        'PaymentReceivable.user_id' => $userId,
32008                        'PaymentReceivable.status' => 0,
32009                        'PaymentReceivable.payment_element_type' => Configure::read('payment_element_type.live'),
32010                        'PaymentReceivable.created <=' => date("Y-m-d H:i:s")
32011                    )
32012                );
32013            }
32014
32015
32016            $ptPaymentParams = json_decode($pt['payment_params'], true);
32017            $currency_before = $user['currency_code'];
32018            $plan_before = $user['payment_plan_id'];
32019
32020            $this->User->openDBReplica();
32021            $currentUser = $this->User->find('first', array(
32022                'fields' => array('User.parent_id', 'User.currency_code', 'User.payment_plan_id','User.memo','User.native_option','User.callan_option'),
32023                'conditions' => array('User.id' => $userId),
32024                'recursive' => -1
32025            ));
32026            $this->User->closeDBReplica();
32027
32028            $parentId = $currentUser['User']['parent_id'];
32029            
32030             
32031            $currency_after = $currentUser['User']['currency_code'];
32032            $plan_after = $currentUser['User']['payment_plan_id'];
32033            $nativeOptionBefore = $nativeOptionAfter = $currentUser['User']['native_option'];
32034            $callanOptionBefore = $callanOptionAfter = $currentUser['User']['callan_option'];
32035
32036
32037            // check if membership status was change
32038            if (isset($ptPaymentParams['statusBefore']) && isset($ptPaymentParams['statusAfter']) && isset($ptPaymentParams['platform'])) {
32039
32040                $usclData = array(
32041                    'user_id' => $userId,
32042                    'platform' => $platform ?? '',
32043                    'card_company_before' => $user['card_company'],
32044                    'status_before' => $ptPaymentParams['statusBefore'],
32045                    'status_after' => $ptPaymentParams['statusAfter'],
32046                    'controller_name' => $this->request->params['controller'],
32047                    'action_name' => $this->request->params['action'],
32048                    'is_cron' => $is_cron,
32049                    'currency_before' => $currency_before,
32050                    'currency_after' => $currency_after,
32051                    'payment_plan_id_before' => $plan_before,
32052                    'payment_plan_id_after' => $plan_after,
32053                );
32054                // save user change membership status
32055                if (!$this->UserStatusChangeLog->saveLog($usclData)) {
32056                    $dataSource->rollback();
32057                    return $result;
32058                }
32059            }
32060
32061            $isLitePlanUser = in_array($plan_after,Configure::read('lite_payment_plans')) ? true : false;
32062            $offUnlimitedOptionNativeFlg = (isset($data['offUnlimitedOptionNative']) && $data['offUnlimitedOptionNative']) ? true : false;
32063            $offUnlimitedOptionCallanFlg = (isset($data['offUnlimitedOptionCallan']) && $data['offUnlimitedOptionCallan']) ? true : false;
32064            $giveLiteMonthlyCoinFlg = (isset($data['giveLiteMonthlyCoin']) && $data['giveLiteMonthlyCoin']) ? true : false;
32065            $removeAllHeldCoinsFlg = (isset($data['removeAllHeldCoins']) && $data['removeAllHeldCoins']) ? true : false;
32066
32067            $currentMemo = $currentUser['User']['memo'];
32068            $updateMemo = '';
32069            $memoCoins = 'MC';
32070            $userUpdateArr = array();
32071            $isNativeOptionChange = $isCallanOptionChange = false;
32072            $today = date('Y-m-d');
32073
32074            // - turn off native option if it is on
32075            if ($offUnlimitedOptionNativeFlg && (int) $nativeOptionBefore == 1) {
32076                    $userUpdateArr['native_option'] = 0; // turn off
32077                    $userUpdateArr['native_option_cancellation_time'] = $dateNow;
32078                    $nativeOptionAfter = 0;
32079                    $isNativeOptionChange = true;
32080
32081                    // set memo
32082                    $updateMemo = $updateMemo. "\n{$today} \nChanged by due Selected Light Plan / Native Unlimited option OFF";
32083            }
32084
32085            // - turn off callan option if it is on
32086            if ($offUnlimitedOptionCallanFlg && (int) $callanOptionBefore == 1) {
32087                $userUpdateArr['callan_option'] = 0; // turn off
32088                $userUpdateArr['callan_option_cancellation_time'] = $dateNow;
32089                $callanOptionAfter = 0;
32090                $isCallanOptionChange = true;
32091
32092                $updateMemo = $updateMemo. "\n{$today} \nChanged by due Selected Light Plan / Callan Unlimited option OFF";
32093            }
32094
32095    
32096            // - confiscate lite plan bonus coin 
32097            if ($removeAllHeldCoinsFlg || $formType == Configure::read('payment_lite_plan_downgrade')) {
32098                    // - fetch users mc coins
32099                    $_monthlyPoints = $this->UsersPoint->getCurrentUserMCPoint($userId); //  mc coins
32100
32101                    if ((int) $_monthlyPoints > 0) {
32102                    
32103                        $confiscateParams = array(
32104                            'userId' => $userId,
32105                            'point' => $_monthlyPoints,
32106                            'kbn' => 18, 
32107                            'coinType' => 3
32108                        );
32109
32110                        // rollback if confiscating points failed
32111                        if (!$confiscateCoinFlg = $this->UsersPoint->confiscateUserLitePoints($confiscateParams)) {
32112                            $this->log(__METHOD__ . ' Failed to confiscate points. --> ' . json_encode($confiscateParams) . ' -- ' . json_encode($data), $logFileName);
32113                                    
32114                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to confiscate points.', $data);
32115                            $dataSource->rollback();
32116                            
32117                            return $result;
32118                        }
32119
32120                        $updateMemo = $updateMemo . "\n {$dateNow} (Previous Coins ({$memoCoins})【Confiscated】 : {$_monthlyPoints}. )";
32121                    }
32122
32123                    $_doneConfiscatePoints = ClassRegistry::init('UsersPointHistory')->confiscateUserLitePointsCoinBox($userId);
32124            }
32125
32126            // - NJ-18780 : add monthly coin for lite plan user 
32127            if ($formType == Configure::read('payment_lite_plan_downgrade')) {
32128                        
32129                    // - set to add monthly coin
32130                    $_pointParams = array(
32131                        'userId' => $userId,
32132                        'point' => Configure::read('lite_plan_monthly_coin'),
32133                        'kbn' => Configure::read('lite_plan_bonus_kbn'), // 
32134                        'kbnType' => 1, // add coin
32135                        'coinType' => 3, // mc coin
32136                        'dateExpiration' => $liteNxtChargeDate,
32137                        'coinFailMessage' => Configure::read('coin.failed.membership')
32138                    );
32139
32140
32141                    // rollback if adding  points failed
32142                    if (!$addCoinsFlg = $this->UsersPoint->performPointTransaction($_pointParams)) {
32143                        $this->log(__METHOD__ . ' Failed to give points. --> ' . json_encode($confiscateParams) . ' -- ' . json_encode($data), $logFileName);
32144                                    
32145                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to give points.', $data);
32146                        $dataSource->rollback();
32147                            
32148                        return $result;
32149                    }
32150
32151                    $_coins = Configure::read('lite_plan_monthly_coin');
32152                    $updateMemo = $updateMemo . "\n {$dateNow} | Light Plan Bonus Coins (MC): {$_coins}";
32153            }
32154
32155    
32156            // - update user memo
32157            if (!empty($updateMemo)) {
32158                $updateMemo = $updateMemo . "\n" . $currentMemo;
32159                $this->User->read(array('memo'), $userId);
32160                $this->User->set(array('memo' => $updateMemo));
32161                $this->User->validate = array();
32162
32163                // rollback if updating memo failed
32164                if (!$this->User->save()) {
32165                    $this->log(__METHOD__ . ' Failed update user memo. ' . json_encode($updateMemo) . ' -- ' . json_encode($data), $logFileName);
32166                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed update user memo.', $data);
32167                    $dataSource->rollback();
32168                    return $result;
32169                }
32170            }
32171
32172            // - update user information
32173            if ($userUpdateArr) {
32174                $userUpdateArr['id'] = $userId;
32175
32176                $this->User->clear();
32177                $this->User->set($userUpdateArr);
32178                $this->User->validate = array();
32179
32180                // rollback if updating memo failed
32181                if (!$this->User->save()) {
32182                    $this->log(__METHOD__ . ' Failed update user info. ' . json_encode($userUpdateArr) . ' -- ' . json_encode($data), $logFileName);
32183                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed update user memo.', $data);
32184                    $dataSource->rollback();
32185                    return $result;
32186                }
32187            }
32188
32189            // - add native option change log
32190            if ($isNativeOptionChange) {
32191                // add native option change logs
32192                if ($nativeOptionAfter) {
32193                    $nativeStatus = 1; // subscribed
32194                    $statusBefore = $option_before_name = '';
32195                    $option_after_name = 'Native Unlimited Option';
32196                    $statusAfter = 1; //
32197                } else {
32198                    $nativeStatus = 3; // unsubscribed
32199                    $statusBefore = 1;
32200                    $option_before_name = 'Native Unlimited Option';
32201                    $option_after_name = $statusAfter = '';
32202                }
32203
32204
32205                $optionLogParams = array(
32206                    'user_id' => $userId,
32207                    'platform' => Configure::read('platform.pclp'),
32208                    'status' => $nativeStatus,
32209                    'controller_name' => $this->request->params['controller'],
32210                    'action_name' => $this->request->params['action'],
32211                    'user_type' => 0, // user
32212                    'option_before' => $statusBefore,
32213                    'option_after' => $statusAfter,
32214                    'option_before_name' => $option_before_name,
32215                    'option_after_name' => $option_after_name,
32216                    'option_type' => 1,
32217                    'payment_plan_id' => $plan_after
32218                );
32219
32220                $aveLog = ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
32221
32222                // rollback if confiscating points failed
32223                if (!$aveLog) {
32224                    $this->log(__METHOD__ . ' Failed to save user option change log. --> ' . json_encode($optionLogParams) . ' -- ' . json_encode($data), $logFileName);
32225                                
32226                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save option log.', $optionLogParams);
32227                    $dataSource->rollback();
32228                        
32229                    return $result;
32230                }
32231            }
32232
32233
32234            // - add callan option change log
32235            if ($isCallanOptionChange) {
32236                // add callan option change logs
32237                if ($callanOptionAfter) {
32238                    $callanStatus = 1; // subscribed
32239                    $statusBefore = $option_before_name = '';
32240                    $option_after_name = 'Callan Unlimited Option';
32241                    $statusAfter = 1; //
32242                } else {
32243                    $callanStatus = 3; // unsubscribed
32244                    $statusBefore = 1;
32245                    $option_before_name = 'Callan Unlimited Option';
32246                    $option_after_name = $statusAfter = '';
32247                }
32248
32249                $optionLogParams = array(
32250                    'user_id' => $userId,
32251                    'platform' => Configure::read('platform.pclp'),
32252                    'status' => $callanStatus,
32253                    'controller_name' => $this->request->params['controller'],
32254                    'action_name' => $this->request->params['action'],
32255                    'user_type' => 0, // user
32256                    'option_before' => $statusBefore,
32257                    'option_after' => $statusAfter,
32258                    'option_before_name' => $option_before_name,
32259                    'option_after_name' => $option_after_name,
32260                    'option_type' => 2,
32261                    'payment_plan_id' => $plan_after
32262                );
32263
32264                $aveLog = ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
32265
32266                // rollback if confiscating points failed
32267                if (!$aveLog) {
32268                    $this->log(__METHOD__ . ' Failed to save user option change log. --> ' . json_encode($optionLogParams) . ' -- ' . json_encode($data), $logFileName);
32269                                
32270                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save option log.', $optionLogParams);
32271                    $dataSource->rollback();
32272                        
32273                    return $result;
32274                }
32275            }
32276
32277            $ptUpdateParams = array(
32278                'id' => $mpptId,
32279                'fields' => array(
32280                    'status' => 1,
32281                    'response_text' => $createOrderResult
32282                ),
32283                'logFileName' => $logFileName
32284            );
32285
32286            // update monthly payment payment transaction
32287            if (!$this->PaymentTransaction->updateWPPaymentTransaction($ptUpdateParams)) {
32288                $this->log(__METHOD__ . ' Failed to update payment transaction. --> ' . json_encode($ptUpdateParams), $logFileName);
32289                $dataSource->rollback();
32290                return $result;
32291            }
32292
32293            //- change to chocotto camp plan
32294            if (in_array(
32295                    $formType,
32296                    [
32297                        Configure::read('payment_credit_chocotto_monthly_payment'),
32298                        Configure::read('payment_credit_chocotto_retry'),
32299                    ]
32300            )) {
32301                //- confiscate lite points
32302                UserTable::changePlanProcess(['user_id' => $userId]);
32303            }
32304
32305            try {
32306                $dataSource->commit();
32307            } catch (\Throwable $th) {
32308                $this->log(__METHOD__ . ' Catch transaction error. --> ' . json_encode($th->getMessage()), $logFileName);
32309            }
32310
32311            $result['success'] = true;
32312        } else {
32313            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Paypal change plan process - failed to create order', $paypalData, $createOrderParams);
32314        }
32315
32316        // delete memcache
32317        if ($this->memcache->get('process_change_plan_'.$userId)) {
32318            $this->memcache->delete('process_change_plan_'.$userId);
32319        }
32320
32321        return $result;
32322    }
32323
32324    private function zeus_payment_change_plan($data = array(),$user=array()){
32325
32326        $logFileName = 'monthly_payment';
32327
32328        if (!$user || !$data) {
32329            $this->log(__METHOD__ . ' Missing billing agreement param(s). --> ' . json_encode($user), $logFileName);
32330            return false;
32331        }
32332
32333        $formType = $data['formType'] ?? null;
32334
32335        if (!$formType) {
32336            $this->log(__METHOD__ . ' Missing form type param(s). --> ' . json_encode($data), $logFileName);
32337            return false;
32338        }
32339
32340        if (!$data['statusAfter']) {
32341            $this->log(__METHOD__ . ' Missing statusAfter param(s). --> ' . json_encode($data), $logFileName);
32342            return false;
32343        }
32344
32345        if (!$data['paymentPlanData']) {
32346            $this->log(__METHOD__ . ' Missing paymentPlanData param(s). --> ' . json_encode($data), $logFileName);
32347            return false;
32348        }
32349
32350        if (!isset($data['totalPayment'])) {
32351            $this->log(__METHOD__ . ' Missing totalPayment param(s). --> ' . json_encode($data), $logFileName);
32352            return false;
32353        }
32354
32355        if (!isset($data['charge_payment_flg'])) {
32356            $this->log(__METHOD__ . ' Missing charge_payment_flg param(s). --> ' . json_encode($data), $logFileName);
32357            return false;
32358        }
32359
32360        $result = false;
32361
32362        // - init var 
32363        $currencyCode = $user['currency_code'];
32364         $priceId = $data['paymentPlanData']['priceId'];
32365         $paymentPlanId = $data['paymentPlanData']['paymentPlanId'];
32366        $currency_before = $user['currency_code'];
32367        $plan_before = $payingUser['User']['payment_plan_id'];
32368        $discountAmount = $monthlyPayment = $totalPayment = 0;
32369        $sendId = $user['id'];
32370
32371        // - update user for creating payment transaction
32372        $user['payment_plan_id'] = $data['paymentPlanData']['paymentPlanId'];
32373        $user['price_id'] = $data['paymentPlanData']['priceId'];
32374
32375        $monthlyPayment = $totalPayment = $data['totalPayment'];
32376        $email = $user['email'];
32377        $clientIp = PaymentTable::getClientIpByCompanyId($user["card_company"]);
32378        $familyId = null;
32379
32380        $nativeOptionPayment = $callanOptionPayment = 0;
32381        $chargePaymentFlg = (isset($data['charge_payment_flg']) && $data['charge_payment_flg']) ? 1 : 0;
32382
32383
32384          $paymentParams = array(
32385            'currencyCode' => $currencyCode,
32386            'formType' => $formType,
32387            'paymentType' => Configure::read('payment_types.payment_plan'),
32388            'logFileName' => $logFileName,
32389            'paymentAmount' => $totalPayment,
32390            'familyId' => $familyId,
32391            'priceId' => $priceId,
32392            'paymentPlanId' => $paymentPlanId,
32393            'nativeOptionPayment' => $nativeOptionPayment,
32394            'callanOptionPayment' => $callanOptionPayment,
32395            'platform' => $user['platform'],
32396            'statusBefore' => $data['statusBefore'],
32397            'statusAfter' => $data['statusAfter'],
32398            'changePlanChargeFlg' => $chargePaymentFlg 
32399          );
32400
32401        if (isset($data['discountOption'])) {
32402            $paymentParams['discountOption'] = $data['discountOption'];
32403            $paymentParams['discountOption'] += [
32404                'dosh_type' => Configure::read('discount_option.dosh_type.plan_change'),
32405                'dosh_status' => Configure::read('discount_option.dosh_status.subscription'),
32406                'option_after_name' => 'Annual Discount Option',
32407                'option_type' => 3
32408            ];
32409        }
32410
32411          $userId =  $sendId;
32412
32413          $paymentHash = myTools::generateOrderCode($userId);
32414
32415        $ptParams = array(
32416            'user_id' => $userId,
32417            'payment_hash' => $paymentHash,
32418            'payment_params' => json_encode($paymentParams),
32419            'course_id' => Configure::read("credit.course_id")
32420        );
32421
32422
32423        // create payment transaction
32424        if (!$pt = $this->PaymentTransaction->setWPPaymentTransaction($ptParams)) {
32425              $this->log(__METHOD__ . ' Failed to create payment transaction . --> ' . json_encode($ptParams), $logFileName);
32426            return false;
32427        }
32428
32429        $this->log(__METHOD__ . '  payment transaction. --> ' . json_encode($pt), $logFileName);
32430
32431        $result = false;
32432
32433        $params = array(
32434            'clientIp' => $clientIp,
32435            'email' => $email,
32436            'sendId' => $sendId,
32437            'money' => $totalPayment,
32438            'paymentHash' => $paymentHash
32439        );
32440
32441         // perform curl request
32442          $curlPayment = ZChargeComponent::charge_with_regsterd_card(json_encode($params));
32443
32444          if ($curlPayment === "Success_order") {
32445              $result = true;
32446          }
32447
32448         // delete memcache
32449        if ($this->memcache->get('process_change_plan_'.$userId)) {
32450            $this->memcache->delete('process_change_plan_'.$userId);
32451        }
32452
32453
32454        return [
32455            'success' => $result,
32456            'paymentHash' => $paymentHash
32457        ];
32458    }
32459    /**
32460     * @api {get} /payment/payment_credit_register_receivable payment_credit_register_receivable()
32461     * @apiName payment_credit_register_receivable
32462     * @apiGroup Payment
32463     * @apiDescription This endpoint is used to redirect to zeus_credit_change or wp_credit_change based on user currency.
32464     * 
32465     * @apiParam {String} [disabled] If set, the page will be disabled.
32466     * 
32467     * @apiSuccess {View} Redirect Redirects to zeus_credit_change for jpy currency
32468     * @apiSuccess {View} Redirect Redirects to wp_credit_change for all other currencies
32469     * 
32470     * @apiError {View} Redirect Redirects to {{ENV}}/ if user membership type is not in payment_receivable
32471     * 
32472     * @apiSuccessExample Success Response JPY currency:
32473     * Redirects to zeus_credit_change
32474     * 
32475     * @apiSuccessExample Success Response All other currencies:
32476     * Redirects to wp_credit_change
32477     * 
32478     * @apiErrorExample Error Response:
32479     * Redirects to {{ENV}}/
32480     * 
32481     * @apiSampleRequest off
32482     */
32483    public function payment_credit_register_receivable() {
32484        $this->blockWithdrawnSapuriToS();
32485        $this->disablePageForSapuri();
32486        $user = $this->sharedUserData['User'];
32487        $userObj = new UserTable($user);
32488        if(!empty($user['corporate_id']) && in_array($userObj->getMembershipTypeIndex(), Configure::read('common_corporate_payment_memberships'))) {
32489            return $this->redirect(myTools::getUrl() . '/common_corporate_payment?type=' . Configure::read('payment_url_type.corporate_type.corporate_change_payment_credit'));
32490        }
32491        
32492        if (!$memcache_receivable_data = $this->memcache->get('memcache_receivable_data' . $user['id'])) {
32493            throw new NotFoundException();
32494        }
32495
32496        $zeusMaintenance = false;
32497        if (myTools::zeusMaintenancePeriod()){
32498            $zeusMaintenance = true;
32499        }
32500        $isCardRegistered = false;
32501        if ((!empty($user['card_brand']) && !empty($user['card_number']))) {
32502            $isCardRegistered = true;
32503        }
32504
32505        $telecomDisabled = false;
32506        $formType = Configure::read('payment_credit_change');
32507        $requestData = $this->request->query;
32508        if (!isset($requestData["disabled"])) {
32509            $this->checkUser($formType);
32510        } else {
32511            $telecomDisabled = true;
32512        }
32513
32514        $userObj = new UserTable($user);
32515        $membershipType = $userObj->getMembershipTypeIndex();
32516        if (!in_array($membershipType, Configure::read('membership_type.payment_receivable'))) {
32517            return $this->redirect('/');
32518        }
32519
32520        $users_detail = $userObj->individualCardFailFlg();
32521        $this->set('individual_card_fail_flg', $users_detail['individual_card_fail_flg'] ?? 0);
32522
32523        $this->getAndSetCardInfo($user);
32524
32525        $this->set('zeus_maintenance', $zeusMaintenance);
32526        $this->set('corporateFlg', myTools::getCoporateTypeUsingPaymentPlanId($user['payment_plan_id']));
32527        $this->set('isCardRegistered', $isCardRegistered);
32528        $this->set("telecomDisabled", $telecomDisabled);
32529        $this->set("membershipType", $membershipType);
32530        $this->set('zeusTransactionFlag', true);
32531        $this->setSupportPayPal($userData);
32532
32533        $zeroStudentDiscountOptionUser = false;
32534
32535        // if light plan user
32536        if (in_array($membershipType, Configure::read('membership_type_lightplan'))) {
32537            // get user active zero student discount option data
32538            $zeroStudentDiscountOptionTermData = $this->UserDiscountOptionsTerm->getTerm([
32539                'user_id' => $userObj->id,
32540                'discount_option_id' => Configure::read('discount_option.zero_student.plan_id'),
32541                'status' => 1
32542            ]);
32543
32544            // set to true if zero student discount option user
32545            if ($zeroStudentDiscountOptionTermData) {
32546                $zeroStudentDiscountOptionUser = true;
32547            }
32548        }
32549
32550        $this->set('zeroStudentDiscountOptionUser', $zeroStudentDiscountOptionUser);
32551
32552        // redirect to zeus if currency is equals to jpy
32553        if ($this->sharedUserData['User']['currency_code'] == Configure::read('default.user_currency')) {
32554            $this->zeus_credit_change();
32555        // redirect to wp
32556        } else {
32557            $this->wp_credit_change();
32558        }
32559    }
32560    /**
32561     * @api {post} /payment/createCorporateIndividualPayment/:corporatePlan createCorporateIndividualPayment()
32562     * @apiName createCorporateIndividualPayment
32563     * @apiGroup Payment
32564     * @apiDescription This endpoint is used to create corporate individual payment.
32565     * 
32566     * @apiParam {String} [corpMobApp] If set, the payment is for mobile app.
32567     * @apiParam {String} [userApiToken] User API token.
32568     * @apiParam {String} corporatePlan Corporate plan type (light, premium, standard).
32569     * 
32570     * @apiSuccess {String} paymentHash The payment hash.
32571     * @apiSuccess {Number} paymentAmount The payment amount.
32572     * 
32573     * @apiError {String} paymentHash The payment hash. Empty if payment is not created.
32574     * @apiError {Number} paymentAmount The payment amount. 0 if payment is not created.
32575     * 
32576     * @apiSuccessExample Success Response:
32577     * {
32578     *   "paymentHash": "some_payment_hash",
32579     *   "paymentAmount": 1000
32580     * }
32581     * 
32582     * @apiErrorExample Success Response:
32583     * {
32584     *   "paymentHash": "",
32585     *   "paymentAmount": 0
32586     * }
32587     */
32588    public function createCorporateIndividualPayment($data) {
32589        $this->autoLayout = false;
32590        $this->autoRender = false;
32591
32592        $corporateTaxRate = Configure::read('tax.increase');
32593
32594        if( isset($data['corpMobApp']) ) {
32595            if( isset($data['userData']) ) {
32596                $user = $data['userData'];
32597            } else {
32598                $mobAppUserData = $this->User->findByApiToken($data['userApiToken']);
32599                $user = $mobAppUserData['User'];
32600            }
32601            $corpSessionKeyMobApp = 'mobappUserCreditChargeInfo_'.$data['userApiToken'];
32602        } else {
32603            $user = $this->sharedUserData['User'];
32604            $corpSessionKey = 'PaymentCreditChargeCorporateData';
32605        }
32606
32607        if( isset($data['ZPaymentFullLogs']['corporatePlan']) ) {
32608
32609            if($data['ZPaymentFullLogs']['corporatePlan'] == 'light') {
32610                $getPaymentPlanId = $this->getCorporatePaymentPlan($user,array('corporate_type' => 4));
32611                $getLightCorporateData = $this->Corporate->getCorporateLightUserMonthly(array(
32612                    'user_id' => $user['id'],
32613                    'remove_heavy_flg' => true
32614                ));
32615                $paymentLightAmount = isset($getLightCorporateData['total']) ? $getLightCorporateData['total'] : 0;
32616                $basicLightFee = isset($getLightCorporateData['basic_fee']) ? $getLightCorporateData['basic_fee'] : 0;
32617                $lessonLightFee = isset($getLightCorporateData['lesson_fee']) ? $getLightCorporateData['lesson_fee'] : 0;
32618                $basicLightFeeWoTax = isset($getLightCorporateData['basic_fee_discounted']) ? $getLightCorporateData['basic_fee_discounted'] : 0;
32619                $freeLightNumber = isset($getLightCorporateData['fee_charge_count']) ? $getLightCorporateData['fee_charge_count'] : 0;
32620                $isLightFreeFlg = isset($getLightCorporateData['free_charge_flg']) ? $getLightCorporateData['free_charge_flg'] : false;
32621                $monthlyLightFee = isset($getLightCorporateData['monthly_fee_wo_tax']) ? $getLightCorporateData['monthly_fee_wo_tax'] : 0;
32622                $cfLightAmount = myTools::formatAmount($basicLightFeeWoTax);
32623                $cLightRawAmount = $basicLightFeeWoTax;
32624                $lessonLightLimit = $this->Corporate->getLessonLimit($user['corporate_id']);
32625                $cpData = array(
32626                    'basicFee' => $basicLightFee,
32627                    'lessonFee' => $lessonLightFee,
32628                    'freeFlg' => $isLightFreeFlg,
32629                    'freeNumber' => $freeLightNumber,
32630                    'monthlyFee' => $monthlyLightFee,
32631                    'fAmount' => $cfLightAmount,
32632                    'paymentAmount' => $paymentLightAmount,
32633                    'lessonLimit' => $lessonLightLimit,
32634                    'paymentPlanId' => $getPaymentPlanId['paymentPlanId'],
32635                    'cRawAmount'    => $cLightRawAmount,
32636                    'basicFeeWoTax' => $basicLightFeeWoTax,
32637                    'priceId'        => $getPaymentPlanId['priceId']
32638                );
32639
32640                $data['ZPaymentFullLogs']['indiCorpType'] = 4;
32641            } else if($data['ZPaymentFullLogs']['corporatePlan'] == 'premium') {
32642                $cpPremuimData = $this->getCorporatePaymentPlan($user,array('corporate_type' => 2));
32643                
32644                $cdrPremiumParam = array('corporateId' => $user['corporate_id'], 'corporateType' => 2);
32645                $discountPremium = (int)$this->CorporateDiscountRate->getDiscount($cdrPremiumParam);
32646                $cPremiumAmount = (int)$cpPremuimData['amount'] - $discountPremium;
32647                $cPremiumRawAmount = $cPremiumAmount;
32648                $cfPremiumAmount = myTools::formatAmount($cPremiumAmount);
32649                $cpData = array(
32650                    'cprAmount' => $cpPremuimData['amount'],
32651                    'cprDiscount' => $discountPremium,
32652                    'paymentAmount' => $cPremiumAmount * $corporateTaxRate,
32653                    'fAmount' => $cfPremiumAmount,
32654                    'cRawAmount' => $cPremiumRawAmount,
32655                    'ppAmount' => $cpPremuimData,
32656                    'paymentPlanId' => $cpPremuimData['paymentPlanId'],
32657                    'priceId'        => $cpPremuimData['priceId']
32658                );
32659
32660                $data['ZPaymentFullLogs']['indiCorpType'] = 2;
32661            } else {
32662                $cpStandardData = $this->getCorporatePaymentPlan($user,array('corporate_type' => 1));
32663                $cdrStandardParam = array('corporateId' => $user['corporate_id'], 'corporateType' => 1);
32664                $discountStandard = (int)$this->CorporateDiscountRate->getDiscount($cdrStandardParam);
32665                $cStandardAmount = (int)$cpStandardData['amount'] - $discountStandard;
32666                $cStandardRawAmount = $cStandardAmount;
32667                $cfStandardAmount = myTools::formatAmount($cStandardAmount);
32668                $cpData = array(
32669                    'cprAmount' => $cpStandardData['amount'],
32670                    'cprDiscount' => $discountStandard,
32671                    'paymentAmount' => $cStandardAmount * $corporateTaxRate,
32672                    'fAmount' => $cfStandardAmount,
32673                    'cRawAmount' => $cStandardRawAmount,
32674                    'ppAmount' => $cpStandardData,
32675                    'paymentPlanId' => $cpStandardData['paymentPlanId'],
32676                    'priceId'        => $cpStandardData['priceId']
32677                );
32678                $data['ZPaymentFullLogs']['indiCorpType'] = 1;
32679            }
32680
32681            $corpIndiPrices = $this->Session->read('corporateIndiPrices');
32682            $corpIndiPrices[$data['ZPaymentFullLogs']['corporatePlan']]['plan_type'] = $data['ZPaymentFullLogs']['indiCorpType'];
32683
32684            if( isset($data['corpMobApp']) ) {
32685                $this->memcache->set(array(
32686                    'key' => $corpSessionKeyMobApp,
32687                    'value' => $corpIndiPrices[$data['ZPaymentFullLogs']['corporatePlan']],
32688                    'expire' => 3600 // 1 hour
32689                ));
32690                $corporateChargeMemData = $this->memcache->get('mobappCreditChargeCorporateData_' . $user['id']);
32691            } else {
32692                $this->Session->write($corpSessionKey,$corpIndiPrices[$data['ZPaymentFullLogs']['corporatePlan']]);
32693            }
32694
32695        }
32696
32697        // change payment plan id and price id
32698        $user['price_id'] = $cpData['priceId'];
32699        $user['payment_plan_id'] = $cpData['paymentPlanId'];
32700        $user['corporate_type'] = $data['ZPaymentFullLogs']['indiCorpType'];
32701        $user['corporateSettlementType'] = Configure::read('corporate_settlement_types.force_charge_payment');
32702
32703        $formType = myTools::getCorporateCompanyCardFormType($cpData['paymentPlanId']);
32704
32705        if ( $this->Session->check($corpSessionKey) || $corporateChargeMemData ) {
32706            // get reserve payment receivable
32707            $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($user['id']);
32708            // get live lesson payment receivable
32709            $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($user['id'], false, Configure::read('appreciation_data.payment_element_type'));
32710            // get live lesson payment receivable
32711            $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($user['id'], false, Configure::read('payment_element_type.live'));
32712
32713            if( isset($data['corpMobApp']) ) {
32714                $corporateIndiPaymentData = $corporateChargeMemData;
32715            } else {
32716                $corporateIndiPaymentData = $this->Session->read($corpSessionKey);
32717            }
32718            $user['paymentAmount'] = (int)$corporateIndiPaymentData['paymentAmount'] + $receivablePayment;
32719
32720            $this->log('[LoyD] createCorporateIndividualPayment cpData --> '.json_encode($cpData));
32721
32722            // corporate light
32723            if (
32724                $corporateIndiPaymentData['plan_type'] == Configure::read('corporate_type.light') &&
32725                isset($corporateIndiPaymentData['lessonFee']) &&
32726                isset($corporateIndiPaymentData['basicFee'])
32727            ) {
32728                $user['lesson_fee'] = (int)$corporateIndiPaymentData['lessonFee'];
32729                $user['basic_fee'] = (int)$corporateIndiPaymentData['basicFee'];
32730            // standard or premium
32731            } else {
32732                if (isset($corporateIndiPaymentData['cprAmount']) && isset($corporateIndiPaymentData['cprDiscount'])) {
32733                    $user['cprAmount'] = (int)$corporateIndiPaymentData['cprAmount'];
32734                    $user['cprDiscount'] = (int)$corporateIndiPaymentData['cprDiscount'];
32735                }
32736            }
32737            $membershipTypes = UserTable::getEngMembershipTypeData();
32738            $user['statusAfter'] =  myTools::getCorporateUserMembershipStatusName($membershipTypes, $user['payment_plan_id']);
32739
32740            $userTable = new UserTable($user);
32741            // add statusBefore and statusAfter if free "Trial not yet conducted"
32742            if ($userTable->getMembershipTypeIndex() == 13) {
32743                $user['statusBefore'] = $membershipTypes[13];
32744                $user['statusAfter'] = myTools::getCorporateUserMembershipStatusName($membershipTypes, $user['payment_plan_id']);
32745            }
32746        }
32747
32748        // - NJ-23812: write session to skip and auto charge check
32749        // set transaction error to 1 if failed to create payment transaction
32750        if (!$pt = $this->createPaymentTransaction($formType, $user)) {
32751            $this->set('transactionError', 1);
32752        }
32753
32754        if( isset($data['corpMobApp']) ) {
32755            $this->memcache->set(array(
32756                'key' => 'indiCorpPaymentHash_'.$user['id'],
32757                'value' => isset($pt['payment_hash']) ? $pt['payment_hash'] : "",
32758                'expire' => 3600 // 1 hour
32759            ));
32760        } else {
32761            $this->Session->write('indiCorpPaymentHash', isset($pt['payment_hash']) ? $pt['payment_hash'] : "");
32762        }
32763
32764        $response = [
32765            'paymentHash' => isset($pt['payment_hash']) ? $pt['payment_hash'] : "",
32766            'paymentAmount'    => (int)$cpData['paymentAmount']
32767        ];
32768
32769        return $response;
32770    }
32771
32772    private function getDefaultPlanId($corporateId = null) {
32773        // default selected plans for null corporate type
32774        $defaultPlan = Configure::read('payment_plans.corporate_premium_individual_plan');
32775
32776        // get corporate admin payment method
32777        $this->Corporate->openDBReplica();
32778        $getActivePlans = $this->Corporate->find('first',
32779                [
32780                    'fields' => [
32781                        'cs_display_flg',
32782                        'cp_display_flg',
32783                        'clt_display_flg',
32784                    ],
32785                    'conditions' => [
32786                        'id' => $corporateId
32787                    ],
32788                    'recursive' => -1
32789                ]
32790            );
32791        $this->Corporate->closeDBReplica();
32792
32793        if(isset($getActivePlans['Corporate']['cs_display_flg']) && $getActivePlans['Corporate']['cs_display_flg']) {
32794            $defaultPlan = Configure::read('payment_plans.corporate_standard_individual_plan');
32795        } else if(isset($getActivePlans['Corporate']['cp_display_flg']) && $getActivePlans['Corporate']['cp_display_flg']){
32796            $defaultPlan = Configure::read('payment_plans.corporate_premium_individual_plan');
32797        } else if(isset($getActivePlans['Corporate']['clt_display_flg']) && $getActivePlans['Corporate']['clt_display_flg']){
32798            $defaultPlan = Configure::read('payment_plans.corporate_light_individual_plan');
32799        }
32800        return $defaultPlan;
32801    }
32802
32803    private function selectCorpType($planId = null) {
32804        $defaultCorpType = Configure::read('corporate_type.premium');
32805        if (in_array($planId, array(Configure::read('payment_plans.corporate_standard_individual_plan'), Configure::read('payment_plans.corporate_standard_card_plan')))) {
32806            $defaultCorpType = Configure::read('corporate_type.standard');
32807        } else if ($planId == Configure::read('payment_plans.corporate_premium_individual_plan')) {
32808            $defaultCorpType = Configure::read('corporate_type.premium');
32809        } else if (in_array($planId, array(Configure::read('payment_plans.corporate_light_individual_plan'), Configure::read('payment_plans.corporate_light_card_plan')))) {
32810            $defaultCorpType = Configure::read('corporate_type.light');
32811        }
32812        return $defaultCorpType;
32813    }
32814    /**
32815     * @api {post} /payment/createLitePlanTransaction/:userId/:formType/:isNewRegister/ createLitePlanTransaction()
32816     * @apiName createLitePlanTransaction
32817     * @apiGroup Payment
32818     * @apiDescription This endpoint is used to create lite plan transaction.
32819     * 
32820     * @apiParam {String} userId User ID.
32821     * @apiParam {String} formType Form type.
32822     * @apiParam {String} isNewRegister If set to 1, the user is a new register.
32823     * @apiParam {String} [studentDiscountOptionData] Student discount option data.
32824     * 
32825     * @apiSuccess {String} paymentHash The payment hash.
32826     * @apiSuccess {Number} paymentMonthlyAmount The payment monthly amount.
32827     * 
32828     * @apiError {String} paymentHash The payment hash. Empty if payment is not created.
32829     * @apiError {Number} paymentMonthlyAmount The payment monthly amount. 0 if payment is not created.
32830     * 
32831     * @apiSuccessExample Success Response:
32832     * {
32833     *      "paymentHash": "some_payment_hash",
32834     *         "paymentMonthlyAmount": 1000
32835     * }
32836     * 
32837     * @apiErrorExample Success Response:
32838     * {
32839     *         "paymentHash": "",
32840     *         "paymentMonthlyAmount": 0
32841     * }
32842     */
32843    public function createLitePlanTransaction($params = []){
32844        $userID = isset($params['userId']) ? $params['userId'] : null;
32845        $formType = isset($params['formType']) ? $params['formType'] : null;
32846        $isNewRegister = isset($params['isNewRegister']) ? $params['isNewRegister'] : false;
32847        $studentDiscountOptionData = isset($params['studentDiscountOptionData']) ? $params['studentDiscountOptionData'] : [];
32848
32849        $result = array();
32850
32851        $logs = array(
32852            'userID' => $userID,
32853            'formType' => $formType,
32854            'isNewRegister' => $isNewRegister
32855        );
32856
32857        if ($userID) {
32858            
32859            #default plan id 
32860            $plan_id = null;
32861            $statusAfter = null;
32862            $membershipTypes = UserTable::getEngMembershipTypeData();
32863
32864            # Step 0 : set the correct form type
32865            if ($isNewRegister) {
32866                if ($studentDiscountOptionData) {
32867                    $formType = Configure::read('payment_lite_credit_monthly_payment');
32868                    $plan_id = Configure::read('payment_plans.light_plan');
32869                    $statusAfter = $membershipTypes[37]; // light plan paid
32870                } else {
32871                    # set the correct form type for newly register
32872                    $formType = Configure::read('payment_lite_credit_free');
32873                    $plan_id = Configure::read('payment_plans.light_plan_free');
32874                    $statusAfter = $membershipTypes[36];
32875                }
32876            }else{
32877
32878                $plan_id = Configure::read('payment_plans.light_plan');
32879                $statusAfter = $membershipTypes[37];
32880
32881                # set the correct form type for charge 
32882                if ($formType == Configure::read('payment_credit_force_charge')) {
32883                    $formType = Configure::read('payment_lite_credit_paid');
32884                }
32885            }
32886
32887            # Step 1 fetch user data 
32888            $userData = $this->User->findById($userID);
32889
32890            # validate user 
32891            if ($userData) {
32892                $userData = $userData['User'];
32893
32894                # Step 2 : prepare to create payment transaction
32895                $userTable = new UserTable($userData);
32896                $membershipTypeIndex = $userTable->getMembershipTypeIndex();
32897
32898                # fetch the plan details
32899                $logFileName = 'card_reregister';
32900
32901                // get free trial payment data
32902                $planData = $this->PaymentPlanPrice->getPaymentData(array(
32903                    'currencyCode' => $userData['currency_code'],
32904                    'paymentPlanId' => $plan_id,
32905                    'logFileName' => $logFileName
32906                ));
32907
32908                if (!$planData) {
32909                    return $result;
32910                }
32911
32912                $userData['price_id'] = $planData['priceId'];
32913                $userData['payment_plan_id'] = $planData['paymentPlanId'];
32914                $userData['statusBefore'] = $membershipTypes[$membershipTypeIndex];
32915                $userData['statusAfter'] = $statusAfter;
32916                $userData['paymentAmount'] = $planData['amount'];
32917
32918                if ($isNewRegister && $studentDiscountOptionData) {
32919                    $planData['amount'] = $userData['paymentAmount'] = 0;
32920                    $userData['discountOption'] = $studentDiscountOptionData;
32921                    $userData['userRegister'] = true;
32922                }
32923
32924                # Step 3  create payment transaction
32925                $pt = $this->createPaymentTransaction($formType, $userData);
32926
32927                if ($pt) {
32928                    # return the payment hash and the amount
32929                    $result['payment_hash'] = $pt['payment_hash'];
32930                    $result['payment_monthly_amount'] = $planData['amount'];
32931                }
32932            }
32933        }
32934
32935        return $result;
32936    }
32937    /**
32938     * @api {post} /payment/applyCouponPayment applyCouponPayment()
32939     * @apiName applyCouponPayment
32940     * @apiGroup Payment
32941     * @apiDescription This endpoint is used to apply coupon payment.
32942     * 
32943     * @apiBody {String} token User token.
32944     * @apiBody {String} totalAmount Total amount of the payment.
32945     * @apiBody {String} couponAmount Coupon amount to be used.
32946     * @apiBody {String} [isUseAllCoupon] If set to 1, all available coupon points will be used.
32947     * 
32948     * @apiSuccess {Boolean} success Indicates if the coupon was applied successfully.
32949     * @apiSuccess {Number} totalCouponUsed The total amount of coupons used.
32950     * @apiSuccess {String} totalCouponUsedFomat The formatted total amount of coupons used.
32951     * @apiSuccess {String} availableCouponPoints The formatted available coupon points.
32952     * @apiSuccess {String} totalAmountFormat The formatted total amount after applying the coupon.
32953     * @apiSuccess {Number} totalAmount The total amount after applying the coupon.
32954     * 
32955     * @apiError {Boolean} success Indicates if the coupon was applied successfully.
32956     * 
32957     * @apiSuccessExample Success Response:
32958     * {
32959     *   "success": true,
32960     *   "totalCouponUsed": 100,
32961     *   "totalCouponUsedFomat": "100",
32962     *   "availableCouponPoints": "50",
32963     *   "totalAmountFormat": "150",
32964     *   "totalAmount": 150
32965     * }
32966     * 
32967     * @apiErrorExample Error Response:
32968     * {
32969     *   "success": false
32970     * }
32971     */
32972    public function applyCouponPayment() {
32973        $this->layout = false;
32974        $this->autoRender = false;
32975        $response = ['success' => false];
32976
32977        if ($this->request->is('post')) {
32978            $data = $this->request->data;
32979            $apiToken = !empty($this->request->query['token']) ? $this->request->query['token'] : null;
32980
32981            $user_id = null;
32982            $user_currency_code = null;
32983            if (!empty($this->sharedUserData['User']['id'])) {
32984                $user_id = $this->sharedUserData['User']['id'];
32985                $user_currency_code = $this->sharedUserData['User']['currency_code'];
32986            } else if (!empty($apiToken)) {
32987                $userData = $this->User->getUserDataByApiToken($apiToken);
32988
32989                if (!empty($userData['User']['id'])) {
32990                    $user_id = $userData['User']['id'];
32991                    $user_currency_code = $userData['User']['currency_code'];
32992                }
32993            }
32994            
32995            // available coupon points
32996            $availableCouponPoints = $this->UsersCouponV1->availableCoupon($user_id);
32997
32998            if ($availableCouponPoints > 0) {
32999                $couponData = $this->Session->read('apply_coupon_usage_data');
33000
33001                if (empty($couponData)) {
33002                    // Get Coupon Used
33003                    $totalCouponUsedParams = [
33004                        'userId'            => $user_id,
33005                        'kbn'                => Configure::read('coupon_kbn.monthly_settlement')
33006                    ];
33007                    $couponRequestData = $this->UsersCouponV1->getCouponUseRequest($totalCouponUsedParams);
33008                    $totalCouponUsed = !empty($couponRequestData['amount']) ? $couponRequestData['amount'] : 0;
33009
33010                    $couponData = [
33011                        'previousUsedCoupon' => $totalCouponUsed,
33012                        'logFileName' => 'heync',
33013                        'availableCouponPoints' => $availableCouponPoints
33014                    ];
33015                }
33016
33017                $couponData['userId'] = $user_id;
33018                $couponData['paymentAmount'] = !empty($data['totalAmount']) ? $data['totalAmount'] : 0;
33019
33020                if (isset($data['isUseAllCoupon']) && $data['isUseAllCoupon'] == 1) {
33021                    if (isset($data['totalAmount']) && $data['totalAmount'] > 0) {
33022                        $couponData['kbn'] = Configure::read('coupon_kbn.monthly_settlement'); // monthly charge kbn
33023
33024                        if ($couponData['availableCouponPoints'] >= $data['totalAmount']) {
33025                            $couponData['useCouponAmount'] = $data['totalAmount'];
33026                        } else {
33027                            $couponData['useCouponAmount'] = $couponData['availableCouponPoints'];
33028                        }
33029
33030                        $response['success'] = true;
33031                    }
33032                } else {
33033                    // use selected coupon amount
33034                    if (isset($data['couponAmount']) && $data['couponAmount'] > 0) {
33035                        $couponData['kbn'] = Configure::read('coupon_kbn.monthly_settlement'); // monthly charge kbn
33036                        
33037                        // apply coupon amount
33038                        if ($data['couponAmount'] > $availableCouponPoints) {
33039                            $couponData['useCouponAmount'] = $availableCouponPoints;
33040                        } else {
33041                            $couponData['useCouponAmount'] = $data['couponAmount'];
33042                        }
33043                        
33044                        // validate if the paymentAmount is greater than the coupon amount
33045                        if ($couponData['paymentAmount'] < $couponData['useCouponAmount']) {
33046                            $couponData['useCouponAmount'] = $couponData['paymentAmount'];
33047                        }
33048
33049                        $response['success'] = true;
33050                    }
33051                }
33052            }
33053        }
33054
33055        if ($response['success'] == true) {
33056            $this->Session->write('apply_coupon_usage_data',$couponData);
33057
33058            // worldpay payment using coupon settlement
33059            if ($wpCouponSettlement = $this->Session->read('wp_coupon_settlement_payment')) {
33060
33061                if (isset($wpCouponSettlement['payment_hash']) && isset($wpCouponSettlement['payment_amount'])) {
33062                    $paymentAmount = $wpCouponSettlement['payment_amount'];
33063
33064                    if (isset($couponData['useCouponAmount']) && $couponData['useCouponAmount'] > 0 && $paymentAmount > 0) {
33065                        if ($paymentAmount >= $couponData['useCouponAmount']) {
33066                            $paymentAmount -= $couponData['useCouponAmount'];
33067                        } else {
33068                            $paymentAmount = 0;
33069                        }
33070                    }
33071
33072                    $currencyExponents = Configure::read('worldpay.currency_exponents');
33073                    $exponent = $currencyExponents[$user_currency_code];
33074
33075                    // get total amount with checking currency exponent
33076                    $totalAmountArr = myTools::wpGetAmount($exponent, $paymentAmount);
33077                    $wpPaymentAmount = $totalAmountArr['wpAmount'];
33078
33079                    $paymentParamsData = [
33080                        'couponUseSettlement' => $couponData,
33081                        'wpPaymentAmount' => $wpPaymentAmount,
33082                        'paymentAmount' => $paymentAmount
33083                    ];
33084
33085                    $this->PaymentTransaction->updatePaymentParams(array('paymentHash' => $wpCouponSettlement['payment_hash'], 'updateData' => $paymentParamsData));
33086                }
33087            }
33088
33089            $response['totalCouponUsed'] = $couponData['previousUsedCoupon'] + $couponData['useCouponAmount'];
33090            $response['totalCouponUsedFomat'] = myTools::formatAmount($couponData['previousUsedCoupon'] + $couponData['useCouponAmount']);
33091            $response['availableCouponPoints'] = myTools::formatAmount($couponData['availableCouponPoints'] - $couponData['useCouponAmount']);
33092            $response['totalAmountFormat'] = myTools::formatAmount($couponData['paymentAmount'] - $couponData['useCouponAmount']);
33093            $response['totalAmount'] = $couponData['paymentAmount'] - $couponData['useCouponAmount'];
33094        }
33095
33096        return json_encode($response);
33097    }
33098
33099    public function setCouponUseData($user_id = null, $currency_code = 'JPY') {
33100        $couponSymbol = myTools::getNewCurrencySymbol($currency_code);
33101        $availableCouponPoints = $this->UsersCouponV1->availableCoupon($user_id);
33102
33103        // Get Coupon Used
33104        $totalCouponUsedParams = [
33105            'userId'            => $user_id,
33106            'kbn'                => Configure::read('coupon_kbn.monthly_settlement')
33107        ];
33108        
33109        $couponRequestData = $this->UsersCouponV1->getCouponUseRequest($totalCouponUsedParams);
33110        $totalCouponUsed = !empty($couponRequestData['amount']) ? $couponRequestData['amount'] : 0;
33111        
33112        if ($totalCouponUsed) {
33113            // confiscate the coupon pending request when student is re-enrolled
33114            $res_confiscate = $this->UsersCouponV1->confiscateAllCoupon(array(
33115                'userId' => $user_id,
33116                'action_type' => 1 // only the pending request will be confiscated
33117            ));
33118            $totalCouponUsed = 0;
33119        }
33120
33121        $couponData = [
33122            'previousUsedCoupon' => $totalCouponUsed,
33123            'availableCouponPoints' => $availableCouponPoints
33124        ];
33125
33126        $readSkipConfirmation = $this->Session->read('credit_skip_to_confirmation');
33127
33128        if (!$this->request->is('post') && !$readSkipConfirmation) {
33129            $this->Session->write('apply_coupon_usage_data', $couponData);
33130        }
33131        
33132        $this->set('couponSymbol',$couponSymbol);
33133        $this->set('availableCouponPoints',$availableCouponPoints);
33134        $this->set('totalCouponUsed',$totalCouponUsed);
33135    }
33136    // NJ-32737-end
33137    /**
33138     * @api {post} /payment/paypal-webhook paypalWebhook()
33139     * @apiName paypalWebhook
33140     * @apiGroup Payment
33141     * @apiDescription This endpoint is used to handle paypal webhook notification.
33142     * 
33143     * @apiBody {String} id The unique identifier for the webhook event
33144     * @apiBody {String} event_version The version of the event
33145     * @apiBody {String} create_time The time the event was created
33146     * @apiBody {String} resource_type The type of resource associated with the event
33147     * @apiBody {String} event_type The type of event that occurred
33148     * @apiBody {String} summary A summary of the event
33149     * @apiBody {Object} resource The resource data associated with the event
33150     * @apiBody {String} resource.id The billing agreement ID
33151     * @apiBody {String} resource.state The state of the billing agreement
33152     * @apiBody {String} resource.description The description of the billing agreement
33153     * @apiBody {String} resource.start_date The start date of the billing agreement
33154     * @apiBody {Object} resource.payer The payer information
33155     * @apiBody {String} resource.payer.payment_method The payment method used
33156     * @apiBody {String} resource.payer.status The status of the payer
33157     * @apiBody {Object} resource.payer.payer_info The payer's information
33158     * @apiBody {String} resource.payer.payer_info.email The payer's email
33159     * @apiBody {String} resource.payer.payer_info.payer_id The payer's ID
33160     * @apiBody {String} resource.payer.payer_info.first_name The payer's first name
33161     * @apiBody {String} resource.payer.payer_info.last_name The payer's last name
33162     * @apiBody {Object} resource.plan The plan information
33163     * @apiBody {Object[]} resource.plan.payment_definitions The payment definitions
33164     * @apiBody {String} resource.plan.payment_definitions.type The type of payment
33165     * @apiBody {String} resource.plan.payment_definitions.frequency The frequency of the payment
33166     * @apiBody {Object} resource.plan.payment_definitions.amount The amount of the payment
33167     * @apiBody {String} resource.plan.payment_definitions.amount.currency The currency of the payment
33168     * @apiBody {String} resource.plan.payment_definitions.amount.value The value of the payment
33169     * @apiBody {Object[]} links Hypermedia links related to the event
33170     * @apiBody {String} links.href The URL of the link
33171     * @apiBody {String} links.rel The relationship of the link
33172     * @apiBody {String} links.method The HTTP method to use for the link
33173     * 
33174     * @apiSuccess {Number} statusCode 200 If webhook notification is successful
33175     * 
33176     * @apiError {Number} statusCode 400 Bad Request if headers or webhook data are invalid
33177     * @apiError {Number} statusCode 400 Bad Request if webhook validation fails
33178     * @apiError {Number} statusCode 400 Bad Request if billing agreement ID is missing
33179     * @apiError {Number} statusCode 500 Internal Server Error if user data does not exist
33180     * 
33181     * @apiExample {json} Example usage:
33182     * {
33183     *       "id": "WH-1234-5678-9012-3456",
33184     *       "event_version": "1.0",
33185     *       "create_time": "2023-10-01T12:34:56Z",
33186     *       "resource_type": "billing_agreement",
33187     *       "event_type": "BILLING_AGREEMENTS.AGREEMENT.CANCELLED",
33188     *       "summary": "A billing agreement was cancelled",
33189     *       "resource": {
33190     *             "id": "I-BW452GLLEP1G",
33191     *             "state": "Cancelled",
33192     *             "description": "Billing Agreement",
33193     *             "start_date": "2023-10-01T00:00:00Z",
33194     *             "payer": {
33195     *               "payment_method": "paypal",
33196     *               "status": "verified",
33197     *               "payer_info": {
33198     *                     "email": "payer@example.com",
33199     *                     "payer_id": "123456789",
33200     *                     "first_name": "John",
33201     *                     "last_name": "Doe"
33202     *               }
33203     *             },
33204     *             "plan": {
33205     *               "payment_definitions": [
33206     *                     {
33207     *                   "type": "REGULAR",
33208     *                   "frequency": "Month",
33209     *                   "amount": {
33210     *                         "currency": "USD",
33211     *                         "value": "10.00"
33212     *                    }
33213     *                  }
33214     *               ]
33215     *                 }
33216     *           },
33217     *       "links": [
33218     *        {
33219     *           "href": "https://api.paypal.com/v1/notifications/webhooks-events/WH-1234-5678-9012-3456",
33220     *           "rel": "self",
33221     *           "method": "GET"
33222     *        }
33223     *       ]
33224     * }
33225     * 
33226     * @apiSuccessExample Success Response:
33227     * Returns status code 200 
33228     * 
33229     * @apiErrorExample Error Response if headers or webhook data are invalid:
33230     * Returns status code 400
33231     * 
33232     * @apiErrorExample Error Response if webhook validation fails:
33233     * Returns status code 400
33234     * 
33235     * @apiErrorExample Error Response if billing agreement ID is missing:
33236     * Returns status code 400
33237     * 
33238     * @apiErrorExample Error Response if user data does not exist:
33239     * Returns status code 500
33240     */
33241    public function paypalWebhook() {
33242        $this->autoLayout = false;
33243        $this->autoRender = false;
33244
33245        $headers = getallheaders();
33246        $webhookData = $this->request->data;
33247
33248        $this->log(__METHOD__ . "PAYPAL WEBHOOK - headers: " . json_encode($headers), 'paypal_debug');
33249        $this->log(__METHOD__ . "PAYPAL WEBHOOK - body: " . json_encode($webhookData), 'paypal_debug');
33250
33251        if (empty($headers) || empty($webhookData)) {
33252            $this->log(__METHOD__ . "- Invalid headers", 'paypal_debug');
33253            return $this->response->statusCode(400);
33254        }
33255
33256        if (!class_exists('PayPal')) {
33257            App::import('Lib', 'PayPal');
33258        }
33259
33260        $paypal = new Paypal();
33261        
33262        $isValidWebhook = $paypal->validatePaypalNotification(array('headers' => $headers, 'data' => $webhookData));
33263        //-- return status code 400 if validate webhook failed
33264        if (!$isValidWebhook) { 
33265            $this->log(__METHOD__ . "- Validate webhook failed", 'paypal_debug');
33266            return $this->response->statusCode(400); 
33267        } 
33268
33269        $billingAgreementId = isset($webhookData['resource']['id']) ? $webhookData['resource']['id'] : null;
33270        if (empty($billingAgreementId)) { 
33271            $this->log(__METHOD__ . "- Billing agreement ID is null", 'paypal_debug');
33272            return $this->response->statusCode(400); 
33273        } 
33274
33275        $this->User->openDBReplica();
33276        $users = $this->User->find('all', array(
33277            'fields' => array(
33278                'User.id',
33279                'User.paypal_billing_agreement_id',
33280                'User.payment_plan_id',
33281                'User.memo',
33282                'User.email',
33283                'User.native_language2'
33284            ),
33285            'conditions' => array('User.paypal_billing_agreement_id' => $billingAgreementId),
33286            'recursive' => -1
33287        ));
33288        $this->User->closeDBReplica();
33289
33290        if (empty($users)) {
33291            $this->log(__METHOD__ . "- User data does not exist", 'paypal_debug');
33292            return $this->response->statusCode(500);
33293        }
33294
33295        // handle webhook notification
33296        switch($webhookData['event_type']) {
33297            // handle cancelled subscription
33298            case 'BILLING_AGREEMENTS.AGREEMENT.CANCELLED': 
33299                $freePlans = array(
33300                    Configure::read('payment_plans.free_trial'),
33301                    Configure::read('payment_plans.free_trial_apple'),
33302                    Configure::read('payment_plans.free_trial_google'),
33303                    Configure::read('payment_plans.weekly_free_trial_apple'),
33304                    Configure::read('payment_plans.weekly_free_trial_google'),
33305                    Configure::read('payment_plans.free_trial_family'),
33306                    Configure::read('payment_plans.studysapuri_biz_free'),
33307                    Configure::read('payment_plans.studysapuri_everyday_free'),
33308                    Configure::read('payment_plans.light_plan_free')
33309                );
33310
33311                foreach($users as $user) {
33312                    // check if user is currently in free trial -> update membership to free
33313                    $paymentPlanID = $user['User']['payment_plan_id'];
33314                    if (in_array($paymentPlanID, $freePlans)) {
33315                        // update main user
33316                        $memo = 'Change status to free from Paypal webhook';
33317                        $userObj = new UserTable($user['User']);
33318                        $native_lang = $userObj->native_language2;
33319
33320                        if ($this->User->updateStatusToFree($userObj, $memo)) {
33321                            if ( 
33322                                $paymentPlanID == Configure::read('payment_plans.free_trial') ||
33323                                $paymentPlanID == Configure::read('payment_plans.light_plan_free')
33324                            ) {
33325                                // send cancellation completion mail
33326                                $userDeactivationFlag = 1;
33327                                $userData['User']['native_language2'] = $native_lang;
33328                                $mail_id = Configure::read('site_in_mail.student_deactivation_complete');
33329                                myMailer::sendTemplateMail($mail_id, $user['User']['email'], $user['User'], array(), 'User', $userDeactivationFlag);
33330                            }
33331                            $this->log(__METHOD__ . '- USER: ' . $userObj->id . ' ' . $memo, 'paypal_debug');
33332                        } else {
33333                            $this->log(__METHOD__ . '- Failed to change user status to free', 'paypal_debug');
33334                        }
33335
33336                        // also update children users if existing
33337                        $childList = $this->User->getChildsDetail($user['User']['id']);
33338                        if(!empty($childList)) {
33339                            foreach($childList as $child) {
33340                                $childUserObj = new UserTable($child['User']);
33341                                if ($this->User->updateStatusToFree($childUserObj, $memo)) {
33342                                    $this->log(__METHOD__ . '- CHILD USER: ' . $childUserObj->id . ' ' . $memo, 'paypal_debug');
33343                                } else {
33344                                    $this->log(__METHOD__ . '- Failed to change child user status to free', 'paypal_debug');
33345                                }
33346                            }
33347                        }
33348
33349                    }
33350                }
33351
33352                break;
33353        }
33354
33355        return $this->response->statusCode(200);
33356    }
33357
33358    /**
33359     * @api {post} /payment/createChocottoPlanTransaction/:userId/:formType/:isNewRegister createChocottoPlanTransaction()
33360     * @apiName createChocottoPlanTransaction
33361     * @apiGroup Payment
33362     * @apiDescription This endpoint is used to create payment transaction for chocotto plan.
33363     * 
33364     * @apiParam {Number} userId The user ID. null if user data does not exist.
33365     * @apiParam {Number} formType The form type. null if form type is invalid.
33366     * @apiParam {Number} isNewRegister The flag to check if user is newly registered. null if flag is invalid.
33367     * 
33368     * @apiSuccess {String} payment_hash The payment hash.
33369     * @apiSuccess {Number} payment_monthly_amount The monthly payment amount.
33370     * 
33371     * @apiError {String} Array returns an empty array
33372     * 
33373     * @apiSuccess {json} Example usage:
33374     * {
33375     *      "payment_hash": "123456789",
33376     *         "payment_monthly_amount": 1000
33377     * }
33378     * 
33379     * @apiErrorExample {json} Error Response:
33380     * {}    
33381     */
33382    public function createChocottoPlanTransaction($params = []){
33383        $userID = isset($params['userId']) ? $params['userId'] : null;
33384        $formType = isset($params['formType']) ? $params['formType'] : null;
33385        $isNewRegister = isset($params['isNewRegister']) ? $params['isNewRegister'] : false;
33386
33387        $result = array();
33388
33389        if ($userID) {
33390            $plan_id = null;
33391            $statusAfter = null;
33392            $membershipTypes = UserTable::getEngMembershipTypeData();
33393
33394            # Step 0 : set the correct form type
33395            if ($isNewRegister) {
33396                # set the correct form type for newly register
33397                $formType = Configure::read('payment_credit_chocotto_free');
33398                $plan_id = Configure::read('payment_plans.free_trial_chocotto');
33399                $statusAfter = $membershipTypes[Configure::read('membership_type_chocotto_plan_free')];
33400            }else{
33401                $plan_id = Configure::read('payment_plans.chocotto_plan');
33402                $statusAfter = $membershipTypes[Configure::read('membership_type_chocotto_plan_paid')];
33403
33404                # set the correct form type for charge 
33405                if ($formType == Configure::read('payment_credit_force_charge')) {
33406                    $formType = Configure::read('payment_credit_chocotto_force_charge');
33407                }
33408            }
33409
33410            # Step 1 fetch user data 
33411            $userData = $this->User->find('first', [
33412                'conditions' => ['User.id' => $userID],
33413                'recursive' => -1
33414            ]);
33415
33416            # validate user 
33417            if ($userData) {
33418                $userData = $userData['User'];
33419
33420                # Step 2 : prepare to create payment transaction
33421                $userTable = new UserTable($userData);
33422                $membershipTypeIndex = $userTable->getMembershipTypeIndex();
33423
33424                # fetch the plan details
33425                $logFileName = 'card_reregister';
33426
33427                // get free trial payment data
33428                $planData = $this->PaymentPlanPrice->getPaymentData(array(
33429                    'currencyCode' => $userData['currency_code'],
33430                    'paymentPlanId' => $plan_id,
33431                    'logFileName' => $logFileName
33432                ));
33433
33434                if (!$planData) {
33435                    return $result;
33436                }
33437
33438                $userData['price_id'] = $planData['priceId'];
33439                $userData['payment_plan_id'] = $planData['paymentPlanId'];
33440                $userData['statusBefore'] = $membershipTypes[$membershipTypeIndex];
33441                $userData['statusAfter'] = $statusAfter;
33442                $userData['paymentAmount'] = $planData['amount'];
33443
33444                if ($isNewRegister) {
33445                    $planData['amount'] = $userData['paymentAmount'] = 0;
33446                    $userData['userRegister'] = true;
33447                }
33448
33449                # Step 3  create payment transaction
33450                $pt = $this->createPaymentTransaction($formType, $userData);
33451
33452                if ($pt) {
33453                    # return the payment hash and the amount
33454                    $result['payment_hash'] = $pt['payment_hash'];
33455                    $result['payment_monthly_amount'] = $planData['amount'];
33456                }
33457            }
33458        }
33459
33460        return $result;
33461    }    
33462
33463
33464    // NJ-23803: Official Webhook from Stripe
33465    // Needs Stripe Signature Verification
33466    public function stripepay() {
33467        $this->autoLayout = false;
33468        $this->autoRender = false;
33469
33470        $this->response->type('application/json');
33471        $this->response->charset('UTF-8');
33472    
33473        $payload = mb_convert_encoding($this->request->input(), 'UTF-8', 'auto');
33474        $this->log(__METHOD__ . ' Stripe Payload: ' . $payload, 'monthly_payment');
33475    
33476        if (!class_exists('Stripe')) {
33477            App::import('Lib', 'Stripe');
33478        }
33479    
33480        $stripe = new Stripe();
33481        if (!$stripe->verifyStripeSignature($payload)) {
33482            $this->log(__METHOD__ . ' Error: Invalid Stripe signature: ' . $payload, 'monthly_payment');
33483            throw new BadRequestException('Invalid signature');
33484        }
33485    
33486        $event = json_decode($payload, true);
33487        if (json_last_error() !== JSON_ERROR_NONE) {
33488            $this->log(__METHOD__ . ' JSON decoding error: ' . json_last_error_msg(), 'monthly_payment');
33489            throw new BadRequestException('Invalid JSON');
33490        }
33491    
33492        switch ($event['type']) {
33493            case 'payment_intent.payment_failed':
33494                $this->log(__METHOD__ . ' Stripe payment failed', 'monthly_payment');
33495                // Handle payment failed
33496                $this->handleStripePaymentResult($event);
33497                break;
33498    
33499            case 'payment_intent.succeeded':
33500                $this->log(__METHOD__ . ' Stripe payment success', 'monthly_payment');
33501                // Handle successful payment
33502                $this->handleStripePaymentResult($event);
33503                break;
33504            
33505            case 'setup_intent.succeeded':
33506                $this->log(__METHOD__ . ' Stripe card authentication success', 'monthly_payment');
33507                // Handle successful card authenticaton
33508                $this->handleStripePaymentResult($event);
33509                break;
33510    
33511            default:
33512                $this->log(__METHOD__ . ' Received unknown event type ' . $event['type'], 'monthly_payment');
33513        }
33514    
33515        // Set the status code and send the response
33516        $this->response->statusCode(200);
33517        $this->response->send();
33518    }
33519
33520    // NJ-23803: Manually Triggered Webhook from CRON
33521    public function stripepay_manual() {
33522        $this->autoLayout = false;
33523        $this->autoRender = false;
33524
33525        $data = $this->request->query;
33526        $this->log(__METHOD__ . ' Stripe Manual Kickback Payload: ' . json_encode($data), 'monthly_payment');
33527        $this->handleStripePaymentResult($data);
33528
33529    }
33530
33531
33532    private function handleStripePaymentResult ($params = array()) {
33533
33534        $data = isset($params['data']['object']) ? $params['data']['object'] : array();
33535        if (empty($data)) {
33536            $this->log(__METHOD__ . ' Stripe Object is empty ', 'monthly_payment');
33537            return;
33538        }
33539
33540        $paymentHash = isset($data['metadata']['sendpoint']) ? trim($data['metadata']['sendpoint']) : null;
33541        $data['ordd'] = $paymentHash;
33542        if (empty($paymentHash)) {
33543            $this->log(__METHOD__ . ' stripe.error.no_payment_hash ', 'monthly_payment');
33544            return;
33545        }
33546
33547        $data['sendid'] = isset($data['metadata']['sendid']) ? $data['metadata']['sendid'] : null;
33548        $moneyAmt = isset($data['metadata']['money']) ? $data['metadata']['money'] : 0;
33549        if (!isset($data['metadata']['money']) && isset($data['amount'])) {
33550            $moneyAmt = $data['amount'];
33551        }
33552        $data['money'] = $moneyAmt;
33553        
33554        if (empty($data['sendid'])) {
33555            $this->log(__METHOD__ . ' stripe.error.no_payment_hash ', 'monthly_payment');
33556            return;
33557        }
33558
33559        $this->sendStripeResponseSlackMessage(array(
33560            'paymentHash' => $paymentHash,
33561            'response' => $data,
33562            'userId' => $data['sendid'],
33563            'action' => 'Stripe Payment Kickback'
33564        ));
33565
33566        $this->loadModel("UsersPoint");
33567        $this->loadModel("Payment");
33568        $this->loadModel("ContinuationCampaign");
33569
33570            
33571        # set variables
33572        $telecom_zeus_convert = false;
33573        $formType = Configure::read('payment_credit_default');
33574        $platform = Configure::read('platform.pclp');
33575        $receivablePayment = $liveLessonReceivable = 0;
33576        $dateNow = date("Y-m-d H:i:s");
33577        $appreciationFlg = 0;
33578        $tipAmount = null;
33579
33580        // prevent switching to replicas inside kickback
33581        $this->PaymentTransaction->setOverrideConnectFlg(true);
33582
33583        // get payment transaction
33584        $ptData = $this->PaymentTransaction->getWPPaymentTransaction($paymentHash);
33585
33586        // if pending payment transaction does not exist try to remove condition to check if has failed transation to override it
33587        if (!$ptData) {
33588            // override the last transaction
33589            $ptData = $this->PaymentTransaction->find('first', array(
33590                'fields' => array(
33591                    'id',
33592                    'user_id',
33593                    'password',
33594                    'payment_params'
33595                ),
33596                'conditions' => array(
33597                    'payment_hash' => $paymentHash
33598                ),
33599                'recursive' => -1
33600            ));
33601
33602            if ($ptData) {
33603                $ptData = $ptData['PaymentTransaction'];
33604            }
33605        }
33606
33607        // do nothing if payment transaction (payment hash and status = 0) does not exist.
33608        if (!$ptData) {
33609            $this->log(__METHOD__ . ' Payment transaction status 0 does not exist. ' . json_encode($data), 'monthly_payment');
33610            // Send to slack only if money is greater than 0
33611            if (isset($data['money']) && $data['money'] > 0) {
33612                $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, 0, 'Payment transaction status 0 does not exist', $data);
33613            }
33614            return ;
33615        }
33616
33617        // decode payment params to array
33618        $ptPaymentParams = json_decode($ptData['payment_params'], true);
33619        $familyId = isset($ptPaymentParams['familyId']) ? $ptPaymentParams['familyId'] : null;
33620        $userId = $familyId ? $familyId : $data['sendid'];
33621        $cardExpirationDate = isset($data['cardexpirationdate']) ? $data['cardexpirationdate'] : null;
33622        $logFileName = isset($ptPaymentParams['logFileName']) ? $ptPaymentParams['logFileName'] : 'monthly_payment';
33623        $basicFee = isset($ptPaymentParams['basicFee']) ? $ptPaymentParams['basicFee'] : 0;
33624        $lessonFee = isset($ptPaymentParams['lessonFee']) ? $ptPaymentParams['lessonFee'] : 0;
33625        $lessonFeeDateStarted = isset($ptPaymentParams['lessonFeeDateStarted']) ? $ptPaymentParams['lessonFeeDateStarted'] : null;
33626        $ptId = $ptData['id'];
33627        $stripePaymentMethod = isset($data['payment_method']) ? $data['payment_method'] : null;
33628        $stripeCustomerID = isset($data['customer']) ? $data['customer'] : null;
33629        
33630        //remove from paying users memcache
33631        UserTable::removePayingUserFromMemcache($userId);
33632
33633        # check the source of the payment
33634        if (isset($ptPaymentParams['formType'])) {
33635            $formType = $ptPaymentParams['formType'];
33636        }
33637
33638        // prevent switching to replicas inside kickback
33639        $this->Payment->setOverrideConnectFlg(true);
33640        
33641        $monthlyPaymentExist = $this->Payment->find('count', array(
33642            'conditions' => array(
33643                'Payment.user_id' => $userId,
33644                'Payment.ordd' => $data['ordd'],
33645                'Payment.card_company' => Configure::read('card_company.stripe'),
33646                'Payment.form_type' => $formType
33647            )
33648        ));
33649        
33650        // NC-4036: do nothing if stripe user and monthly payment transaction (ordd) already exist.
33651        if ($monthlyPaymentExist) {
33652            $this->log(__METHOD__ . ' Payments data already exist. ' . json_encode($data), $logFileName);
33653            $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Payments data already exist', $data);
33654            return ;
33655        }
33656
33657        // NC-8600: if family is withdrawn
33658        if ($formType == Configure::read('payment_credit_family_monthly_payment') && $this->memcache->get('deactivated-user-'.$userId)) {
33659            $this->log(__METHOD__ . ' User is withdrawn. ' . json_encode($data), 'monthly_payment');
33660            $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'User is withdrawn', $data);
33661            return;
33662        }
33663        
33664        // save settlement history for tracking
33665        if (!SettlementHistoryTable::add(array(
33666                'userId' => $userId,
33667                'params' => json_encode($data),
33668                'createdIp' => $dateNow,
33669                'modifiedIp' => $dateNow
33670            )
33671        )) {
33672            $this->log(__METHOD__ . ' Failed to save stripepay kickback data in settlement history. ' . json_encode($data), $logFileName);
33673            $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save zeuspay kickback data in settlement history', $data);
33674            return;
33675        }
33676
33677        # append data parameters
33678        $data += array(
33679                'ip' => isset($ptPaymentParams['remoteAddress']) ? $ptPaymentParams['remoteAddress'] : null,
33680                'user_id' => $userId,
33681                'created' => $dateNow,
33682                'modified' => $dateNow,
33683        );
33684
33685        # check if user exists, and remove any bound models
33686        $userData = $this->User->find("first",array("conditions" =>array("User.id"=>$userId), "recursive" => -1));
33687        if (!$userData) {
33688            $this->log(__METHOD__ . ' User id does not exist. ' . json_encode($userId) . ' -- ' . json_encode($data), $logFileName);
33689            $data['error_code'] = Configure::read('zeus.error.no_user');
33690            $this->stripe_error_log_set($data, $ptPaymentParams);
33691            $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'User id does not exist', $data);
33692            return ;
33693        }
33694
33695        $card_company = isset($data['metadata']['card_company']) ? $data['metadata']['card_company'] : null;
33696        if (empty($card_company) && isset($userData['User']['card_company']) ) {
33697            $card_company = $userData['User']['card_company'];
33698        }
33699
33700        $membershipStatusIndex = UserTable::getStudentMembershipStatus($userId);
33701
33702
33703        # check if ordd is present
33704        if (isset($data['ordd']) === FALSE) {
33705            $data['ordd'] = NULL;
33706        }
33707
33708
33709        # check if payment transaction password exist
33710        $ptPassword = "";
33711        if (isset($ptData['password'])) {
33712            $ptPassword = $ptData['password'];
33713        }
33714
33715        # check if payment type is from payment plan or coin purchase or textbook purchase
33716        if (isset($ptPaymentParams['paymentType'])) {
33717            $paymentType = $ptPaymentParams['paymentType'];
33718        }
33719
33720        # check platform
33721        if (isset($ptPaymentParams['platform'])) {
33722            $platform = $ptPaymentParams['platform'];
33723        }
33724
33725        $paymentPlanId = isset($ptPaymentParams['paymentPlanId']) ? $ptPaymentParams['paymentPlanId'] : null;
33726        $priceId = isset($ptPaymentParams['priceId']) ? $ptPaymentParams['priceId'] : null;
33727        $currencyCode = isset($ptPaymentParams['currencyCode']) ? $ptPaymentParams['currencyCode'] : Configure::read('currency_jpy');
33728        $discounted_amount = isset($ptPaymentParams['discounted_amount']) ? $ptPaymentParams['discounted_amount'] : 0;
33729
33730        // if using coupon during force settlement
33731        if (!empty($ptPaymentParams['couponUseSettlement']) && !empty($ptPaymentParams['couponUseSettlement']['useCouponAmount']) && in_array($formType, Configure::read('allow_coupon.settlement_form_type'))) {
33732            $discounted_amount += $ptPaymentParams['couponUseSettlement']['useCouponAmount'];
33733        }
33734
33735        # NC-8194: check null payment_plan_id and price_id
33736        if (!$paymentPlanId || !$priceId) {
33737            if ( $userData['User']['payment_plan_id'] && $userData['User']['price_id']) {
33738                $paymentPlanId = $userData['User']['payment_plan_id'];
33739                $priceId = $userData['User']['price_id'];
33740            } else {
33741                $defPlan = $this->PaymentPlanPrice->getDefaultPlan($userData['User']);
33742                $paymentPlanId = $defPlan['paymentPlanId'];
33743                $priceId = $defPlan['priceId'];
33744            }
33745        }
33746
33747        # set data variables
33748        $data['paymentType'] = $paymentType;
33749        $data['formType'] = $formType;
33750
33751        // - NJ-18780 : check if lite plan user 
33752        // $isLitePlanUser = in_array($paymentPlanId, Configure::read('lite_payment_plans')) ? true : false;
33753
33754        $cronDateRun = isset($ptPaymentParams['cronDateRun']) ? $ptPaymentParams['cronDateRun'] : $dateNow;
33755
33756        $monthlyPayment = isset($data["money"]) ? $data["money"] : 0;
33757        $nativeOptionPayment = 0;
33758        $callanOptionPayment = 0;
33759
33760        
33761        // if monthly payment, retry or force charge
33762        // check if user has receivable payment
33763        if (in_array($formType, array(
33764            Configure::read('payment_credit_monthly_payment'),
33765            Configure::read('payment_credit_family_monthly_payment'),
33766            Configure::read('payment_credit_force_charge'),
33767            Configure::read('payment_credit_retry'),
33768            Configure::read('payment_credit_change')
33769        ))) {
33770
33771            $_allowChangePlan = true; // NJ-23803: assume true for Phase 1
33772
33773            // compute receivable payments
33774            $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userData['User']['id'], $cronDateRun);
33775
33776            // if has receivable payment
33777            // deduct said monthly settlement from the money sent to zeus
33778            if ($receivablePayment && $receivablePayment <= $data["money"] && $_allowChangePlan) {
33779                // deduct from monthly payment
33780                $monthlyPayment -= $receivablePayment;
33781            }
33782
33783            // if has native speaker payments
33784            // deduct
33785            if (isset($ptPaymentParams['nativeOptionPayment']) && $ptPaymentParams['nativeOptionPayment'] > 0 && $_allowChangePlan) {
33786                $nativeOptionPayment = $ptPaymentParams['nativeOptionPayment'];
33787                $monthlyPayment -= $nativeOptionPayment;
33788            }
33789
33790            // if has callan option payments
33791            // deduct
33792            if (isset($ptPaymentParams['callanOptionPayment']) && $ptPaymentParams['callanOptionPayment'] > 0 && $_allowChangePlan) {
33793                $callanOptionPayment = $ptPaymentParams['callanOptionPayment'];
33794                $monthlyPayment -= $callanOptionPayment;
33795            }
33796
33797            // compute appreciation receivable payments
33798            $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.appreciation'));
33799
33800            if ($appreciationReceivable && $appreciationReceivable <= $monthlyPayment) {
33801                $monthlyPayment -= $appreciationReceivable;
33802            }
33803
33804            // compute live lesson receivable payments
33805            $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userData['User']['id'], $cronDateRun, Configure::read('payment_element_type.live'));
33806
33807            if ($liveLessonReceivable && $liveLessonReceivable <= $monthlyPayment && $_allowChangePlan) {
33808                $monthlyPayment -= $liveLessonReceivable;
33809            }            
33810
33811            $ptPaymentParams['paymentAmount'] = $monthlyPayment;
33812        }
33813
33814        // Check receivables combine on `payment_credit_receivable` form type
33815        if( $formType == Configure::read('payment_credit_receivable') ) {
33816
33817            // compute appreciation receivable payments
33818            $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.appreciation'));
33819
33820            // deduct said receivable settlement from the money sent to zeus
33821            if ($appreciationReceivable && $appreciationReceivable <= $data["money"]) {
33822                // deduct from receivable payment
33823                $monthlyPayment -= $appreciationReceivable;
33824            }
33825
33826            // compute live receivable payments
33827            $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.live'));
33828
33829            // deduct said receivable settlement from the money sent to zeus
33830            if ($liveLessonReceivable && $liveLessonReceivable <= $data["money"]) {
33831                // deduct from receivable payment
33832                $monthlyPayment -= $liveLessonReceivable;
33833            }            
33834
33835            $ptPaymentParams['paymentAmount'] = $monthlyPayment;
33836        }
33837
33838        $kbResult = false;
33839        # check if the result is ok
33840        if ( myTools::checkStripePaymentResponse($data) ) {
33841            $kbResult = true;
33842            $this->log(__METHOD__ . 'result is ok', $logFileName);
33843
33844            # get current card company
33845            $currentCardCompany = is_null($userData['User']['card_company']) ? FALSE : intVal($userData['User']['card_company']);
33846
33847            # check if formType = 5
33848            if ($formType == Configure::read('payment_credit_coin_purchase') && isset($ptPaymentParams['coinPurchasePoints'])) {
33849                
33850                $coinPurchasePoints = intVal($ptPaymentParams['coinPurchasePoints']);
33851                $coinData = $this->UsersPoint->SET_charge_overseas_menue($coinPurchasePoints, $currencyCode);
33852
33853                // NC-5007 add to the user's existing coin
33854                $pcZeusPay = array(
33855                    'userId' => $userData['User']['id'],
33856                    'point' => $coinData['num_of_coin'] - $coinData['bonus_coin'],
33857                    'kbn' => 7,
33858                    'kbnType' => 1, // add coin
33859                    'coinType' => 1, // purchase coin
33860                    'coinFailMessage' => Configure::read('coin.failed.buy_coin'),
33861                    'device' => isset($ptPaymentParams['device']) ? $ptPaymentParams['device'] : null
33862                );
33863
33864                $scZeusPay = array(
33865                    'userId' => $userData['User']['id'],
33866                    'point' => $coinData['bonus_coin'],
33867                    'kbn' => 7,
33868                    'kbnType' => 1, // add coin
33869                    'coinType' => 2, // service coin
33870                    'coinFailMessage' => Configure::read('coin.failed.buy_coin'),
33871                    'device' => isset($ptPaymentParams['device']) ? $ptPaymentParams['device'] : null
33872                );
33873
33874                $pointParams = [$pcZeusPay, $scZeusPay];
33875
33876                if ( $pointParams ) {
33877                    foreach($pointParams as $key => $val) {
33878                        if (!$this->UsersPoint->performPointTransaction($val)) {
33879                            $this->log(__METHOD__ . ' Failed to add user point. ' . json_encode($val) . ' -- ' . json_encode($data), $logFileName);
33880                            $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to add user point', $data, $val);
33881                            return ;
33882                        }
33883                    }
33884                }
33885            }
33886
33887            // check if family plan and a coin purchase form type 
33888            if (
33889                $familyId 
33890                && in_array($formType, array(
33891                        Configure::read('payment_credit_coin_purchase'), 
33892                        Configure::read('payment_credit_textbook_purchase')
33893                    )
33894                )
33895            ) {
33896                // change reference id to parent id
33897                $referenceId = isset($data['sendid']) ? $data['sendid'] : 0;
33898            
33899            //IF Native option or callan option join payment and family
33900            } elseif(
33901                (
33902                    isset($ptPaymentParams['nativeOptionJoin']) 
33903                    && $ptPaymentParams['nativeOptionJoin'] 
33904                    && $familyId
33905                    && $ptPaymentParams['formType'] == Configure::read('payment_native_option_join')
33906                ) 
33907                ||
33908                (
33909                    isset($ptPaymentParams['callanOptionJoin']) 
33910                    && $ptPaymentParams['callanOptionJoin'] 
33911                    && $familyId
33912                    && $ptPaymentParams['formType'] == Configure::read('payment_callan_option_join')
33913                )
33914            ) {
33915                // change reference id to parent id
33916                $referenceId = isset($data['sendid']) ? $data['sendid'] : 0;
33917            } else {
33918                $referenceId = $userId;
33919            }
33920            
33921            $paymentData = array(
33922                'user_id' => $userId,
33923                'amount' => $monthlyPayment,
33924                'status' => 1,
33925                'reference_id' => $referenceId,
33926                'payment_transaction_password' => $ptPassword,
33927                'card_company' => $card_company,
33928                'param1' => json_encode($data),
33929                'form_type' => $formType,
33930                'ordd' => $data["ordd"],
33931                'transaction_code' => $paymentHash,
33932                'currency_id' => Configure::read('default.settlement_currency_id'), // set currency id to jpy
33933                'currency_code' => $currencyCode,
33934                'payment_id' => $paymentPlanId,
33935                'price_id' => $priceId,
33936                'payment_type' => $paymentType,
33937                'discounted_amount' => $discounted_amount
33938            );
33939
33940            $discountOption = isset($ptPaymentParams['discountOption']) ? $ptPaymentParams['discountOption'] : [];
33941            
33942            if (!empty($discountOption)) {
33943                $paymentData['discount_option_price_id'] = $discountOption['discount_option_price_id'];
33944            }
33945            
33946            // NJ-47740
33947            $discountType = 'monthly';
33948            if ($formType == Configure::read('payment_native_option_join')) {
33949                $discountType = 'native';
33950            } else if ($formType == Configure::read('payment_callan_option_join')) {
33951                $discountType = 'callan';
33952            } else if ($formType == Configure::read('payment_credit_coin_purchase')) {
33953                $discountType = 'coin';
33954            }
33955            
33956            $getCouponDiscounDetail = PaymentTable::getCouponDiscountRequestDetail($ptPaymentParams, $discountType);
33957            $paymentData['discounted_amount'] = !empty($getCouponDiscounDetail['discounted_amount']) ? $getCouponDiscounDetail['discounted_amount'] : 0;
33958            $paymentData['coupon_request_id'] = !empty($getCouponDiscounDetail['coupon_request_id']) ? $getCouponDiscounDetail['coupon_request_id'] : null;
33959            
33960            $forceSettlementWithCoupon  = false;
33961            // if using coupon during force settlement
33962            if (
33963                !empty($ptPaymentParams['couponUseSettlement']) && 
33964                !empty($ptPaymentParams['couponUseSettlement']['useCouponAmount']) && 
33965                in_array($formType, Configure::read('allow_coupon.settlement_form_type'))
33966            ) {
33967                // apply coupon use discount
33968                $couponData = $ptPaymentParams['couponUseSettlement'];
33969                $couponData['nextChargeDate'] = date('Y-m-d');
33970                $couponData['request_result'] = true;
33971
33972                $result_coupon_use = $this->UsersCouponV1->performCouponUse($couponData);
33973                $result_coupon_use = !empty($result_coupon_use) ? json_decode($result_coupon_use,true) : array();
33974                
33975                if (empty($result_coupon_use)) {
33976                    $this->log(__METHOD__ . ' Failed to used coupons.' . json_encode($couponData), $logFileName);
33977                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to used coupons.', $couponData, array_merge($_POST, $_SERVER));
33978                    return false;
33979                }
33980                
33981                $paymentData['discounted_amount'] = $ptPaymentParams['couponUseSettlement']['useCouponAmount'];
33982                $paymentData['coupon_request_id'] = isset($result_coupon_use['cgrp_id']) ? $result_coupon_use['cgrp_id'] : null;
33983                
33984                $forceSettlementWithCoupon = true;
33985            }
33986            
33987            // NC-10009 95% OFF new year campaign
33988            // During NC-10009 campaign 
33989            // Temporary -> Premiuim Plan Paid
33990            // Create two payment data for card authentication and for premium plan paid payment
33991            $newYear95percentOffCampaign = false;
33992            if (
33993                (isset($ptPaymentParams['campaign95percentOff']) && $ptPaymentParams['campaign95percentOff'])
33994                && (isset($ptPaymentParams['userRegister']) && $ptPaymentParams['userRegister'])
33995            ) 
33996            {
33997                $newYear95percentOffCampaign = true;
33998                $paymentDataForCardAuthentication = $paymentData;
33999                $paymentDataForCardAuthentication['amount'] = 0;
34000                $paymentDataForCardAuthentication['form_type'] = Configure::read('payment_credit_authentication');
34001                $paymentDataForCardAuthentication['payment_id'] = Configure::read('payment_plans.free_trial');
34002                $paymentDataForCardAuthentication['price_id'] = 1;
34003                // create new for card authentication payment
34004                $this->Payment->clear();
34005                $this->Payment->create();
34006                $this->Payment->set($paymentDataForCardAuthentication);
34007                $this->Payment->save();
34008            }
34009
34010            // NC-7029: save discount amount
34011            if ($discounted_amount > 0) {
34012                $paymentData['discounted_amount'] = $discounted_amount;
34013            }
34014
34015            //- check payment receivable with zero amount
34016            if (
34017                $formType == Configure::read('payment_credit_receivable') &&
34018                $monthlyPayment <= 0
34019            ) {
34020                //- skip saving
34021            } else {
34022                // create new payment
34023                $this->Payment->clear();
34024                $this->Payment->create();
34025                $this->Payment->set($paymentData);
34026                $savePaymentData = $this->Payment->save();
34027
34028                //update/add user`s settlement amount
34029                $this->User->updateUserPayments($paymentData);
34030                // check if payment was not saved
34031                if (!$this->Payment->save()) {
34032                    $this->log(__METHOD__ . ' Failed to save payment data. ' . json_encode($paymentData) . ' -- ' . json_encode($data), $logFileName);
34033                    $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data', $data, $paymentData);
34034
34035                    // if payment failed and has coupon grp id and its direct payment -> unconfirm coupon
34036                    if (
34037                        isset($paymentData['coupon_request_id']) && $paymentData['coupon_request_id'] &&
34038                        (
34039                            // the native or callan purchase with coupon use already has checker while processing the payment
34040                            // to ensure that payment errors are caught, place it here as well to make sure that the coupon is unconfirmed in case the page is refreshed while processing
34041                            in_array(
34042                                $formType, array(
34043                                    Configure::read('payment_native_option_join'),
34044                                    Configure::read('payment_callan_option_join'),
34045                                    Configure::read('payment_credit_coin_purchase')
34046                                )
34047                            ) ||
34048                            // force settlement with coupon
34049                            $forceSettlementWithCoupon
34050                        )
34051                    ) {
34052                        $couponKbn = Configure::read('coupon_kbn.coin_purchase'); // default
34053                        if ($formType == Configure::read('payment_native_option_join')) {
34054                            $couponKbn = Configure::read('coupon_kbn.native_option');
34055                        } else if ($formType == Configure::read('payment_callan_option_join')) {
34056                            $couponKbn = Configure::read('coupon_kbn.callan_option');
34057                        } else if ($forceSettlementWithCoupon) {
34058                            $couponKbn = Configure::read('coupon_kbn.monthly_settlement');
34059                        }
34060                        
34061                        $res_unconfirm = $this->UsersCouponV1->performCouponUnconfirm(array(
34062                            'grpId' => $paymentData['coupon_request_id'],
34063                            'userId' => $userId,
34064                            'kbn' => $couponKbn
34065                        ));
34066
34067                        if (empty($res_unconfirm)) {
34068                            $this->log(__METHOD__ . ' failed to perform coupon unconfirm.', $logFileName);
34069                        }
34070                    }
34071                    return ;
34072                }
34073
34074                // update payment details
34075                $updatePaymentDetailParams = array(
34076                    'currencyCode' => $paymentData['currency_code'],
34077                    'formType' => $paymentData['form_type'],
34078                    'paymentType' => $paymentData['payment_type'],
34079                    'amount' => $paymentData['amount'],
34080                    'discounted_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0,
34081                    'familyId' => $familyId,
34082                    'cronDateRun' => $cronDateRun,
34083                    'priceId' => $paymentData['price_id'],
34084                    'paymentPlanId' => $paymentData['payment_id'],
34085                    'user_id' => $paymentData['user_id'],
34086                    'coupon_use_request_id' => isset($paymentData['coupon_request_id']) ? $paymentData['coupon_request_id'] : null,
34087                    'coupon_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0
34088                );
34089                
34090                if (!empty($discountOption)) {
34091                    $updatePaymentDetailParams['discount_option_price_id'] = $discountOption['discount_option_price_id'];
34092                    $updatePaymentDetailParams['discount_option_amount'] = $discountOption['amount'];
34093                }
34094                $updatePaymentDetail = array(
34095                    'id' => $ptId,
34096                    'fields' => array(
34097                        'payment_details' => $updatePaymentDetailParams
34098                    )
34099                );
34100
34101                if (!$this->PaymentTransaction->updateWPPaymentTransaction($updatePaymentDetail)) {
34102                    $this->log(__METHOD__ . ' Failed to update payment details. ' . json_encode($updatePaymentDetail), $logFileName);
34103                }
34104
34105                // set payment_id
34106                $paymentSaveID = $this->Payment->id;
34107
34108                // NJ-47740
34109                if (!empty($paymentData['coupon_request_id']) && $paymentData['discounted_amount'] > 0) {
34110                    // confirm coupon use request for discount
34111                    $requestCouponConfirmData = array(
34112                        'grpId' => $paymentData['coupon_request_id'],
34113                        'paymentId' => $paymentSaveID
34114                    );
34115                    $result_confirm = $this->UsersCouponV1->performCouponConfirm($requestCouponConfirmData);
34116                    
34117                    if (!$result_confirm) {
34118                        $this->log(__METHOD__ . ' Failed to confirm coupon use request. ' . json_encode($requestCouponConfirmData) . ' -- ' . json_encode($data), $logFileName);
34119                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to confirm coupon use request', $data, $requestCouponConfirmData);
34120                        return ;
34121                    }
34122                }
34123                // NJ-47740 end
34124
34125                // NJ-35237
34126                if (!empty($ptPaymentParams['rewardedPoints'])) {
34127                    $rewaredPointParams['ContinuationRewardPoint'] = $ptPaymentParams['rewardedPoints'];
34128                    // save reward point
34129                    if (!$this->ContinuationRewardPoint->saveRewardPoint($rewaredPointParams)) {
34130                        $this->log(__METHOD__ . ' Failed to save reward point. --> ' . json_encode($ptPaymentParams['rewardedPoints']), $logFileName);
34131                        $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to save reward point. --> ' . json_encode($ptPaymentParams['rewardedPoints']), 'error');
34132                    }
34133                }
34134                // NJ-35237 end
34135
34136                
34137            }
34138
34139            // set transaction
34140            $dataSource = $this->User->getDataSource();
34141            $dataSource->begin();
34142
34143            if (
34144                $formType != Configure::read('payment_credit_textbook_purchase') &&
34145                $formType != Configure::read('payment_credit_receivable') &&
34146                $formType != Configure::read('payment_credit_appreciation_receivable') &&
34147                $formType != Configure::read('payment_credit_coin_purchase') &&
34148                $formType != Configure::read('payment_native_option_join') &&
34149                $formType != Configure::read('payment_native_option_monthly_payment') &&
34150                $formType != Configure::read('payment_callan_option_join') &&
34151                $formType != Configure::read('payment_callan_option_monthly_payment') &&
34152                $formType != Configure::read('payment_halfway_termination_of_annual_discount_option')
34153            ) {
34154
34155                # user array to be saved
34156                $saveUserArr = array(
34157                    'User' => array(
34158                        'status' => 1,
34159                        'modified' => date('YmdHis'),
34160                        'fail_flg' => 0,
34161                        'charge_flg' => 1,
34162                        'counseling_attended_flg' => 0,
34163                        'card_company' => $card_company,
34164                        'hash16' => $userData['User']['id'],
34165                        'last_charge_date' => date('YmdHis'),
34166                        'payment_plan_id' => $paymentPlanId,
34167                        'price_id' => $priceId,
34168                        'corporate_id' => null,
34169                        'corporate_type' => null,
34170                        'paypal_billing_agreement_id' => null,
34171                        'paypal_payer_id' => null,
34172                        'is_new_premium_flg' => 0,
34173                        'double_check_flg' => 1
34174                    )
34175                );
34176
34177                // if not empty card expiration date
34178                if (isset($ptPaymentParams['cardExpirationDate'])) {
34179                    $saveUserArr['User']['card_expiration_date'] = $ptPaymentParams['cardExpirationDate'];
34180                }
34181
34182                // set child card expiration date same as parent
34183                if (isset($ptPaymentParams['family_data']['applyPlan']['card_expiration_date'])) {
34184                    $saveUserArr['User']['card_expiration_date'] = $ptPaymentParams['family_data']['applyPlan']['card_expiration_date'];
34185                }
34186
34187                // ----
34188                # check payment if credit authentication
34189                if (in_array($formType, array(Configure::read('payment_lite_credit_free'),Configure::read('payment_credit_authentication'), Configure::read('payment_credit_family_free')))) {
34190                    $saveUserArr['User']['first_charge_date'] = date('Y-m-d H:i:s');
34191                    $saveUserArr['User']['platform'] = $platform;
34192                // if complimentary plan unsubscribe and resubscribe
34193                } elseif (isset($ptPaymentParams['updateFirstChargeDate']) || $newYear95percentOffCampaign) {
34194                    $saveUserArr['User']['first_charge_date'] = date('Y-m-d H:i:s');
34195                }
34196
34197                // if bonus coin flg is set
34198                if (isset($ptPaymentParams['bonusCoinFlg'])) {
34199                    $saveUserArr['User']['bonus_coin_flg'] = $ptPaymentParams['bonusCoinFlg'];
34200                }
34201
34202                if (!empty($stripePaymentMethod)) {
34203                    $saveUserArr['User']['stripe_payment_identifier'] = $stripePaymentMethod;
34204                }
34205
34206                if (!empty($stripeCustomerID)) {
34207                    $saveUserArr['User']['stripe_customer_id'] = $stripeCustomerID;
34208                }
34209
34210                //NJ-7874 if appreciation flag and amount is set
34211                if (isset($ptPaymentParams['family_data']['applyPlan']['tip_max_amount']) && $ptPaymentParams['family_data']['applyPlan']['tip_max_amount']) {
34212                    $tipAmount = $ptPaymentParams['family_data']['applyPlan']['tip_max_amount'];
34213                }
34214
34215                if (isset($ptPaymentParams['family_data']['applyPlan']['allow_appreciation_flg']) && $ptPaymentParams['family_data']['applyPlan']['allow_appreciation_flg'] && $tipAmount) {
34216                    $appreciationFlg = 1;
34217                }
34218
34219                // get time today plus 1 hour
34220                $nextChargeTime = (time() + 3600) - strtotime('TODAY');
34221                
34222                # check if subscription payment
34223                if (
34224                    $formType == Configure::read('payment_credit_force_charge') ||
34225                    $formType == Configure::read('payment_credit_retry') ||
34226                    $formType == Configure::read('payment_credit_monthly_payment') ||
34227                    $formType == Configure::read('payment_credit_family_monthly_payment') ||
34228                    $formType == Configure::read('payment_credit_family_free')
34229                ) {
34230
34231                    if ($formType == Configure::read('payment_credit_monthly_payment')) {
34232                        $nextChargeTime = strtotime($userData['next_charge_date']) - strtotime('TODAY');
34233                    }
34234
34235                    // set minutes and seconds to 00:00 always
34236                    $nextChargeDate = date('Y-m-d H:00:00', strtotime('+' . $nextChargeTime . ' second ' . $this->User->getNextChargeDate()));
34237
34238                    # get and set next charge date
34239                    $nextChargeDate = $nextChargeDate = date('Y-m-d H:00:00', strtotime('+' . (time() - strtotime('TODAY')) . ' second ' . $this->User->getNextChargeDate()));
34240                    $saveUserArr['User']['next_charge_date'] = $nextChargeDate;
34241                    $saveUserArr['User']['double_check_flg'] = 1;
34242                    $saveUserArr['User']['expired_card_flg'] = 0; // NC-3902
34243
34244                    // NJ-1562 - appreciation on
34245                    if( $paymentPlanId && in_array( $paymentPlanId, Configure::read('appreciation.payment_plan_id') ) ) {
34246                        //$saveUserArr['User']['allow_appreciation_flg'] = 1; // on
34247                        if (in_array($paymentPlanId,Configure::read('appreciation.can_coin_purchase_check')) ) {
34248                            //set the appreciation flg to be set
34249                            $saveUserArr['User']['allow_appreciation_flg'] = $appreciationFlg;
34250                            $saveUserArr['User']['show_appreciation_flg'] = $appreciationFlg;
34251                            $saveUserArr['User']['tip_max_amount'] = $tipAmount;
34252                        }else{
34253                            $saveUserArr['User']['allow_appreciation_flg'] = 1; // on
34254
34255                            if (
34256                                $formType == Configure::read('payment_credit_force_charge') || 
34257                                $formType == Configure::read('payment_credit_retry') || 
34258                                $formType == Configure::read('payment_lite_credit_paid')
34259                            ) {
34260                                $showAppreciationFlg = 0;//set  the default show appreciation flg
34261
34262                                //NJ-7548 : check user birthday and age ; $userData['User']['birthday']
34263                                $userAge = UserTable::getStudentAge($userData['User']['birthday']);
34264                                $userAge = $userAge ? (int) $userAge : null;
34265
34266                                //change the show appreciation flg if no birthday set or 18 and above
34267                                if (!$userAge || $userAge >= 18) {
34268                                    $showAppreciationFlg = 1;
34269                                }
34270
34271                                $saveUserArr['User']['show_appreciation_flg'] = $showAppreciationFlg; // on
34272                            }
34273                        }
34274                    }
34275                    
34276                    if ($formType == Configure::read('payment_credit_family_free')) {
34277                        $nextChargeDate = date('Y-m-d H:00:00', strtotime('+' . $nextChargeTime . ' second ' . $this->User->getFirstNextChargeDate()));
34278                        $saveUserArr['User']['next_charge_date'] = $nextChargeDate;
34279                    }
34280
34281                    # give points to user join the campaign who retry payment
34282                    if ($formType == Configure::read('payment_credit_retry') && !$isLitePlanUser) {
34283                        $this->ContinuationCampaign->givePointsRetrySuccess(array(
34284                            'user_ids' => array($userData['User']['id'])
34285                        ));
34286                    }
34287
34288                    # give points if user join campaign and success payment
34289                    if ($formType == Configure::read('payment_credit_monthly_payment')) {
34290                        $this->ContinuationCampaign->givePoints(array(
34291                            'user_id' => $userData['User']['id']
34292                        )); 
34293                    }
34294
34295                    # give coins if temporary/new user is changed/added to family plan
34296                    if ($formType == Configure::read('payment_credit_family_free') && $userData['User']['status'] == 0) {
34297                        // NJ-4746: defult bonus point
34298                        $defaultBC = ClassRegistry::init("DefaultCoinRegistration")->defaultCoins();
34299                        $bonusPoints = (($defaultBC > 0) ? $defaultBC : Configure::read("credit.bonus_coin_authentication"));
34300
34301                        // camapaign master triiger 1
34302                        $campaignMaster = ClassRegistry::init('CampaignMaster')->bonusTrigger(['userId' => $userData['User']['id'], 'triggerNo' => 1]);
34303                        if (!$campaignMaster['bonusCoins'] && !$campaignMaster['bonusCoupons']) {
34304                            # add to the user's existing coin
34305                            $pointParams = array(
34306                                'userId' => $userData['User']['id'],
34307                                'point' => $bonusPoints,
34308                                'kbn' => Configure::read("point_history.bonus"),
34309                                'kbnType' => 1, // add coin
34310                                'coinType' => 2, // service coin
34311                                'coinFailMessage' => Configure::read('coin.failed.campaign')
34312                            );
34313                            if (!$this->UsersPoint->performPointTransaction($pointParams)) {
34314                                $this->log(__METHOD__ . ' Failed add point to user. ' . json_encode($pointParams) . ' -- ' . json_encode($data), $logFileName);
34315                                $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed add point to user', $data, $pointParams);
34316                                $dataSource->rollback();
34317                                $dataSource->commit();
34318                                return ;
34319                            }
34320                        }
34321                    }
34322
34323                    # give points if user join retry payment lite 
34324                    if ($formType == Configure::read('payment_credit_retry') && $isLitePlanUser) {
34325                        $this->liteUserAddCoinRewardForReenroll(array('id' => $userData['User']['id']));
34326                    }
34327
34328                } elseif (
34329                    $formType ==  Configure::read('payment_credit_authentication') || 
34330                    $formType == Configure::read('payment_lite_credit_free')
34331                ) {
34332                    // set minutes and seconds to 00:00 always
34333                    $nextChargeDate = date('Y-m-d H:00:00', strtotime('+' . $nextChargeTime . ' second ' . $this->User->getFirstNextChargeDate()));
34334                    $saveUserArr['User']['next_charge_date'] = $nextChargeDate;
34335
34336                    // NJ-1562 - appreciation on
34337                    if( $paymentPlanId && in_array( $paymentPlanId, Configure::read('appreciation.payment_plan_id') ) ) {
34338                        //$saveUserArr['User']['allow_appreciation_flg'] = 1; // on
34339                        if (in_array($paymentPlanId,Configure::read('appreciation.can_coin_purchase_check')) ) {
34340                            //set the appreciation flg to be set
34341                            $saveUserArr['User']['allow_appreciation_flg'] = $appreciationFlg;
34342                            $saveUserArr['User']['show_appreciation_flg'] = $appreciationFlg;
34343                            $saveUserArr['User']['tip_max_amount'] = $tipAmount;
34344                        }else{
34345                            $saveUserArr['User']['allow_appreciation_flg'] = 1; // on
34346
34347                            $showAppreciationFlg = 0;
34348
34349                            //NJ:7548: fetch the age of the user
34350                            $uAge = UserTable::getStudentAge($userData['User']['birthday']);
34351                            $uAge = $uAge ? (int) $uAge : null;
34352
34353                            //change the show appreciation flg if no birthday set or 18 and above
34354                            if (!$uAge || $uAge >= 18) {
34355                                $showAppreciationFlg = 1;
34356                            }
34357
34358                            //set the save user array 
34359                            $saveUserArr['User']['show_appreciation_flg'] = $showAppreciationFlg; // set
34360                        }
34361                    }
34362                }
34363
34364                #NJ-7548 : if credit card changed to zeus 
34365                if (
34366                    $formType == Configure::read('payment_credit_change') && 
34367                    $paymentPlanId && in_array( $paymentPlanId, Configure::read('appreciation.payment_plan_id') )
34368                ) {
34369                    
34370                    if (in_array($paymentPlanId,Configure::read('appreciation.can_coin_purchase_check')) ) {
34371                        //set the appreciation flg to be set
34372                        $saveUserArr['User']['allow_appreciation_flg'] = $appreciationFlg;
34373                        $saveUserArr['User']['show_appreciation_flg'] = $appreciationFlg;
34374                        $saveUserArr['User']['tip_max_amount'] = $tipAmount;
34375                    }else{
34376                        $saveUserArr['User']['allow_appreciation_flg'] = 1; // on
34377
34378                        $showAppreciationFlg = 0;//set  the default show appreciation flg
34379
34380                        //NJ-7548 : check user birthday and age ; $userData['User']['birthday']
34381                        $userAge = UserTable::getStudentAge($userData['User']['birthday']);
34382                        $userAge = $userAge ? (int) $userAge : null;
34383
34384                        //change the show appreciation flg if no birthday set or 18 and above
34385                        if (!$userAge || $userAge >= 18) {
34386                            $showAppreciationFlg = 1;
34387                        }
34388
34389                        $saveUserArr['User']['show_appreciation_flg'] = $showAppreciationFlg; // on
34390                    }
34391                }
34392
34393
34394                // if credit card change from android or apple
34395                if (
34396                    in_array($formType, array(Configure::read('payment_credit_change'), Configure::read('payment_credit_authentication'))) &&
34397                    in_array($userData['User']['card_company'], array(Configure::read('card_company.apple'), Configure::read('card_company.google')))
34398                ) {
34399                    // NC-5007 add to user's existing number of coins
34400                    $pointParams = array(
34401                        'userId' => $userData['User']['id'],
34402                        'point' => 500,
34403                        'kbn' => 6,
34404                        'kbnType' => 1, // add coin
34405                        'coinType' => 2, // service coin
34406                        'coinFailMessage' => Configure::read('coin.failed.campaign')
34407                    );
34408                    if (!$this->UsersPoint->performPointTransaction($pointParams)) {
34409                        $this->log(__METHOD__ . ' Failed add point to user. ' . json_encode($pointParams) . ' -- ' . json_encode($data), $logFileName);
34410                        $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed add point to user', $data, $pointParams);
34411                        $dataSource->rollback();
34412                        $dataSource->commit();
34413                        return ;
34414                    }
34415
34416                    // log for debugging
34417                    $this->log("[STRIPEPAY] switching user from android/ios to zeus -> " . json_encode($data), $logFileName);
34418                }
34419
34420                $discountOption = isset($ptPaymentParams['discountOption']) ? $ptPaymentParams['discountOption'] : [];
34421                $zeroStudentDiscount = false;
34422
34423                # update the user information
34424                $this->User->validate = array();
34425                if (!$read = $this->User->read(null, $userData['User']['id'])) {
34426                    $this->log(__METHOD__ . ' User id does not exist. ' . json_encode($userData) . ' -- ' . json_encode($data), $logFileName);
34427                    $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'User id does not exist', $data, $userData);
34428                    $dataSource->rollback();
34429                    $dataSource->commit();
34430                    return ;
34431                }
34432                $currency_before = $userData['User']['currency_code'];
34433                $plan_before = $userData['User']['payment_plan_id'];
34434
34435                $famRegist = false;
34436                // NC-4673: update family parent_id, memo and monthly_payment
34437
34438
34439                if (
34440                    in_array($formType, Configure::read('family_plan_form_types'))
34441                ) {
34442                    // if parent_id is empty
34443                    if (empty($read['User']['parent_id'])) {
34444                        $saveUserArr['User']['parent_id'] = $data['sendid'];
34445                        $saveUserArr['User']['memo'] = date('Y/m/d H:i:s')." Family plan[User]: family registration \n".$read['User']['memo'];
34446                        $famRegist = true;
34447
34448                
34449                        if (empty($read['User']['currency_code'])) {
34450                            $saveUserArr['User']['currency_code'] = $currencyCode;
34451                        }
34452                    }
34453                }
34454
34455                $this->User->set($saveUserArr);
34456                if (!$this->User->save()) {
34457                    $this->log(__METHOD__ . ' Failed update user data. ' . json_encode($saveUserArr) . ' -- ' . json_encode($data), $logFileName);
34458                    $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed update user data', $data, $saveUserArr);
34459                    $dataSource->rollback();
34460                    $dataSource->commit();
34461                    return ;
34462                }
34463
34464                // check if payment plan upgrade
34465                if ($formType == Configure::read('payment_lite_plan_upgrade')) {
34466                    // get user zero student discount term
34467                    $discountOptionTermData = $this->UserDiscountOptionsTerm->getTerm([
34468                        'user_id' =>  $userId,
34469                        'discount_option_id' => Configure::read('discount_option.zero_student.plan_id'),
34470                        'status' => 1
34471                    ]);
34472
34473                    // stop zero student discount
34474                    if ($discountOptionTermData) {
34475                        // open tunnel
34476                        myTools::initializeApiTunnel(['DiscountOptionController']);
34477
34478                        // initialize controller
34479                        $doc = new DiscountOptionController();
34480
34481                        $docParams = [
34482                            'discountOptionId' => $discountOptionTermData['discount_option_id'],
34483                            'discountOptionPriceId' => $discountOptionTermData['discount_option_price_id'],
34484                            'termId' => $discountOptionTermData['discount_option_term_id'],
34485                            'cancellationFee' => 0,
34486                            'cancellationType' => Configure::read('discount_option.dosh_type.plan_change'),
34487                            'userData' => $userData['User'],
34488                            'fromController' => $this->request->params['controller'],
34489                            'fromAction' => $this->request->params['action'],
34490                            'doshStatus' => Configure::read('discount_option.dosh_status.midterm_cancellation')
34491                        ];
34492
34493                        // set data
34494                        $doc->params = $docParams;
34495
34496                        if (!$doc->stopDiscountOption()) {
34497                            $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to stop discount option. ', $docParams);
34498                            $dataSource->rollback();
34499                            $dataSource->commit();
34500                            return ;
34501                        }
34502                    }
34503                }
34504
34505                // if user plan has discount option
34506                if ($discountOption) {
34507                    $contractStart = $formType != Configure::read('payment_credit_authentication') ? date('Y-m-d 00:00:00') : (isset($nextChargeDate) ? $nextChargeDate : $this->User->getFirstNextChargeDate());
34508                    if (
34509                        (
34510                            $discountOption['discount_option_id'] == Configure::read('discount_option.zero_student.plan_id') &&
34511                            $formType == Configure::read('payment_lite_credit_monthly_payment') && 
34512                            isset($ptPaymentParams['userRegister']) &&
34513                            $ptPaymentParams['userRegister']
34514                        ) ||
34515                        in_array(
34516                            $formType,
34517                            [
34518                                Configure::read('payment_credit_authentication'),
34519                                Configure::read('payment_credit_force_charge'),
34520                                Configure::read('payment_lite_plan_upgrade')
34521                            ]
34522                        )
34523                    ) {
34524                        // set amount to 0 if card auth
34525                        if ($formType == Configure::read('payment_credit_authentication')) {
34526                            $discountOption['amount'] = 0;
34527                        }
34528
34529                        // set data for user discount option term
34530                        $udotData = [
34531                            'userId' => $userId,
34532                            'discountOptionId' => $discountOption['discount_option_id'],
34533                            'discountOptionPriceId' => $discountOption['discount_option_price_id'],
34534                            'contractStart' => $contractStart,
34535                            'logFileName' => $logFileName,
34536                            'paymentId' => $paymentSaveID,
34537                            'discountAmount' => $discountOption['amount'],
34538                            'doshEvent' => isset($discountOption['dosh_event']) ? $discountOption['dosh_event'] : null,
34539                            'currencyCode' => $currencyCode,
34540                            'doshStatus' => isset($discountOption['dosh_status']) ? $discountOption['dosh_status'] : null,
34541                            'formType' => $formType,
34542                            'userRegister' => isset($ptPaymentParams['userRegister']) ? true : false
34543                        ];
34544
34545                        if (isset($discountOption['dosh_type'])) {
34546                            $udotData['doshType'] = $discountOption['dosh_type'];
34547                        }
34548
34549                        if (
34550                            $discountOption['discount_option_id'] == Configure::read('discount_option.zero_student.plan_id') &&
34551                            $formType == Configure::read('payment_lite_credit_monthly_payment')
34552                        ) {
34553                            $zeroStudentDiscount = true;
34554                        }
34555
34556                        // create user discount option term
34557                        if (!$this->UserDiscountOptionsTerm->createTerm($udotData)) {
34558                            $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to create user discount option term. ', $udotData);
34559                            $dataSource->rollback();
34560                            $dataSource->commit();
34561                            return ;
34562                        }
34563
34564                        // check if has uploaded data for zero student document(s)
34565                        if (isset($discountOption['application_form_app_image_url'])) {
34566                            $applicationData = [
34567                                'user_id' => $userId,
34568                                'image_url' => $discountOption['application_form_app_image_url']
34569                            ];
34570            
34571                            // save document url
34572                            if (!$this->StudentDiscountApplicationForm->saveApplicationForm($applicationData)) {
34573                                $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save zero student application form. ', $applicationData);
34574                                $dataSource->rollback();
34575                                $dataSource->commit();
34576                                return ;
34577                            }
34578
34579                            $udData = [
34580                                'user_id' => $userId,
34581                                'individual_card_fail_flg'    => 0,
34582                                'show_zero_student_discount_option_flg' => 1
34583                            ];
34584
34585                            $this->UsersDetail->clear();
34586                            $this->UsersDetail->set($udData);
34587                            $this->UsersDetail->validate = [];
34588                            if (!$this->UsersDetail->save()) {
34589                                $this->log(__METHOD__ . ' Failed insert users detail data. ' . json_encode($udData) . ' -- ' . json_encode($data), $logFileName);
34590                                $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to insert users detail data. ', $udData);
34591                                $dataSource->rollback();
34592                                $dataSource->commit();
34593                                return ;
34594                            }
34595
34596                            $slackParams = [
34597                                'userId' => $userId,
34598                                'nickname' => $userData['User']['nickname'],
34599                                'nextChargeDate' => $this->User->getNextChargeDate(),
34600                                'applicationCnt' => 1,
34601                                'appFormUrl' => $discountOption['application_form_app_image_url']
34602                            ];
34603
34604                            // send slack
34605                            StudentDiscountApplicationFormTable::sendSlackStudentDiscountInfo($slackParams);
34606                        }
34607                    } elseif (in_array($formType, [Configure::read('payment_credit_monthly_payment'), Configure::read('payment_credit_retry')])) {
34608                        $discountOption += [
34609                            'contract_start' => $contractStart,
34610                            'currency_code' => $currencyCode,
34611                            'payment_id' => $paymentSaveID,
34612                            'dosh_settlement_status' => 1, // success
34613                            'form_type' => $formType
34614                        ];
34615
34616                        if (!$this->UserDiscountOptionsTerm->processMonthlyDiscountOption($discountOption)) {
34617                            $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to process monthly discount option. ', $discountOption);
34618                            $dataSource->rollback();
34619                            $dataSource->commit();
34620                            return ;
34621                        }
34622                    }
34623
34624                    if (
34625                        (
34626                            in_array(
34627                                $formType,
34628                                [
34629                                    Configure::read('payment_credit_authentication'),
34630                                    Configure::read('payment_credit_force_charge'),
34631                                    Configure::read('payment_lite_plan_upgrade')
34632                                ]
34633                            ) ||
34634                            (
34635                                $discountOption['discount_option_id'] == Configure::read('discount_option.zero_student.plan_id') &&
34636                                $formType == Configure::read('payment_lite_credit_monthly_payment') && 
34637                                isset($ptPaymentParams['userRegister']) &&
34638                                $ptPaymentParams['userRegister']
34639                            )
34640                        ) &&
34641                        isset($discountOption['option_after_name']) &&
34642                        isset($discountOption['option_type'])
34643                    ) {
34644                        $adoLogParams = [
34645                            'user_id' => $userId,
34646                            'platform' => $platform,
34647                            'status' => 1, // subscribe
34648                            'controller_name' => $this->request->params['controller'],
34649                            'action_name' => $this->request->params['action'],
34650                            'user_type' => 0, // normal user
34651                            'option_before' => '',
34652                            'option_after' => 1,
34653                            'option_before_name' => isset($discountOption['option_before_name']) ? $discountOption['option_before_name'] : '',
34654                            'option_after_name' => $discountOption['option_after_name'],
34655                            'option_type' => $discountOption['option_type'],
34656                            'payment_plan_id' => $paymentPlanId
34657                        ];
34658
34659                        if (!$this->UserOptionChangeLog->saveOptionChangeLog($adoLogParams)) {
34660                            $this->log(__METHOD__ . ' Failed to update option change. ' . json_encode($adoLogParams), $logFileName);
34661                            $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'Failed to update user data', $adoLogParams);
34662                            $dataSource->rollback();
34663                            $dataSource->commit();
34664                            return ;
34665                        }
34666                    }
34667                }
34668
34669                # NJ-18780 : changed plan to liteplan
34670                if (
34671                    $formType == Configure::read('payment_lite_plan_downgrade') || 
34672                    $formType == Configure::read('payment_lite_plan_upgrade')
34673                ) {
34674                    $this->User->openDBReplica();
34675                    $_currentUser = $this->User->find('first', array(
34676                        'fields' => array('User.parent_id', 'User.currency_code', 'User.payment_plan_id','User.memo','User.native_option','User.callan_option','next_charge_date'),
34677                        'conditions' => array('User.id' => $userData['User']['id']),
34678                        'recursive' => -1
34679                    ));
34680                        $this->User->closeDBReplica();
34681
34682                    $_memoCoins = 'SC and PC';
34683                    $_updateMemo = '';
34684                    $litenativeOptionBefore = $litenativeOptionAfter = $_currentUser['User']['native_option'];
34685                       $litecallanOptionBefore = $litecallanOptionAfter = $_currentUser['User']['callan_option'];
34686                       $isliteNativeOptionChange = $isliteCallanOptionChange = false;
34687
34688                       $liteUserUpdateArr = array();
34689                       $_dateNow = date("Y-m-d H:i:s");
34690
34691                    // - turn off native option if it is on
34692                    if ((int) $litenativeOptionBefore == 1) {
34693                        $liteUserUpdateArr['native_option'] = 0; // turn off
34694                        $liteUserUpdateArr['native_option_cancellation_time'] = $dateNow;
34695                        $litenativeOptionAfter = 0;
34696                        $isliteNativeOptionChange = true;
34697
34698                        // set memo
34699                        $_updateMemo = $_updateMemo. "\n{$_dateNow} \nChanged by due Selected Light Plan / Native Unlimited option OFF";
34700                    }
34701
34702                    // - turn off callan option if it is on
34703                    if ((int) $litecallanOptionBefore == 1) {
34704                        $liteUserUpdateArr['callan_option'] = 0; // turn off
34705                        $liteUserUpdateArr['callan_option_cancellation_time'] = $dateNow;
34706                        $litecallanOptionAfter = 0;
34707                        $isliteCallanOptionChange = true;
34708
34709                        $_updateMemo = $_updateMemo. "\n{$_dateNow} \nChanged by due Selected Light Plan / Callan Unlimited option OFF";
34710                    }
34711
34712                    // - changing to lite plan
34713                    if ($formType == Configure::read('payment_lite_plan_downgrade')) {
34714                    
34715                        // - confiscate all mc coins
34716                        $_monthlyPoints = $this->UsersPoint->getCurrentUserMCPoint($userData['User']['id']); 
34717                        $_memoCoins = "MC";
34718
34719                        if ((int) $_monthlyPoints > 0) {
34720                            $confiscateParams = array(
34721                                'userId' => $userData['User']['id'],
34722                                'point' => $_monthlyPoints,
34723                                'kbn' => 18, 
34724                                'coinType' => 3
34725                            );
34726
34727
34728                            // rollback if confiscating points failed
34729                            if (!$confiscateCoinFlg = $this->UsersPoint->confiscateUserLitePoints($confiscateParams)) {
34730                                $this->log(__METHOD__ . ' Failed to confiscate points. --> ' . json_encode($confiscateParams) . ' -- ' . json_encode($data), $logFileName);
34731                                        
34732                                $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userData['User']['id'], 'Failed to confiscate points.', $userData);
34733                                $dataSource->rollback();
34734                                $dataSource->commit();
34735                                return ;
34736                            }
34737
34738                            $_updateMemo = $_updateMemo . "\n {$_dateNow} (Previous Coins ({$_memoCoins})【Confiscated】 : {$_monthlyPoints}. )";
34739                        }
34740
34741                        $doneConfiscatePoints = ClassRegistry::init('UsersPointHistory')->confiscateUserLitePointsCoinBox($userData['User']['id']);
34742
34743                        $nextChargeDateLite = $this->User->getNextChargeDate();
34744
34745                        // - give lite bonus coins
34746                        $_pointParams = array(
34747                            'userId' => $userData['User']['id'],
34748                            'point' => Configure::read('lite_plan_monthly_coin'),
34749                            'kbn' => Configure::read('lite_plan_bonus_kbn'), // 
34750                            'kbnType' => 1, // add coin
34751                            'coinType' => 3, // mc coin
34752                            'dateExpiration' => $nextChargeDateLite,
34753                            'coinFailMessage' => Configure::read('coin.failed.membership')
34754                        );
34755
34756                        // rollback if adding  points failed
34757                        if (!$_addCoinsFlg = $this->UsersPoint->performPointTransaction($_pointParams)) {
34758                            $this->log(__METHOD__ . ' Failed to give points. --> ' . json_encode($confiscateParams) . ' -- ' . json_encode($data), $logFileName);
34759                                    
34760                            $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to give points.', $data);
34761                            $dataSource->rollback();
34762                            $dataSource->commit();
34763                            return ;
34764                        }
34765
34766                        $_coins = Configure::read('lite_plan_monthly_coin');
34767                        $updateMemo = $updateMemo . "\n {$_dateNow} | Light Plan Bonus Coins (MC): {$_coins}";
34768                    }
34769
34770                    // - changing from premium to lite plan
34771                    if ($formType == Configure::read('payment_lite_plan_upgrade')) {
34772                        // - confiscate all held coins
34773                        $_monthlyPoints = $this->UsersPoint->getCurrentUserMCPoint($userData['User']['id']); //  mc coins
34774
34775                        $_memoCoins = "MC";
34776
34777                        if ((int) $_monthlyPoints > 0) {
34778                            $confiscateParams = array(
34779                                'userId' => $userData['User']['id'],
34780                                'point' => $_monthlyPoints,
34781                                'kbn' => 18, 
34782                                'coinType' => 3
34783                            );
34784
34785
34786                            // rollback if confiscating points failed
34787                            if (!$confiscateCoinFlg = $this->UsersPoint->confiscateUserLitePoints($confiscateParams)) {
34788                                $this->log(__METHOD__ . ' Failed to confiscate points. --> ' . json_encode($confiscateParams) . ' -- ' . json_encode($data), $logFileName);
34789                                        
34790                                $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userData['User']['id'], 'Failed to confiscate points.', $userData);
34791                                $dataSource->rollback();
34792                                $dataSource->commit();
34793                                return ;
34794                            }
34795
34796                            $_updateMemo = $_updateMemo . "\n {$_dateNow} (Previous Coins ({$_memoCoins})【Confiscated】 : {$_monthlyPoints}. )";
34797                        }
34798
34799                        $_doneConfiscatePoints = ClassRegistry::init('UsersPointHistory')->confiscateUserLitePointsCoinBox($userData['User']['id']);
34800                    }
34801
34802                    #update the user information memo
34803                    if (empty($_updateMemo)) {
34804
34805                        $_updateMemo = $_updateMemo . "\n" . $_currentUser['User']['memo'];
34806                     
34807                        $_userUpdate = array(
34808                            'id' => $userData['User']['id'],
34809                            'memo' => $_updateMemo
34810                        );
34811
34812                        $this->User->set($_userUpdate);
34813                        if (!$this->User->save()) {
34814                            $this->log(__METHOD__ . ' Failed to update user data. ' . json_encode($_userUpdate), $logFileName);
34815                            $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed to update user data', $_userUpdate);
34816                            $dataSource->rollback();
34817                            $dataSource->commit();
34818                            return ;
34819                        }
34820                    }
34821
34822                    // - update the user information
34823                    if ($liteUserUpdateArr) {
34824                        $liteUserUpdateArr['id'] = $userData['User']['id'];
34825
34826                        // - set user 
34827                        $this->User->set($liteUserUpdateArr);
34828
34829                        if (!$this->User->save()) {
34830                            $this->log(__METHOD__ . ' Failed to update user data. ' . json_encode($liteUserUpdateArr), $logFileName);
34831                            $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed to update user data', $_userUpdate);
34832                            $dataSource->rollback();
34833                            $dataSource->commit();
34834                            return ;
34835                        }
34836                    }
34837
34838                    # add log if there is change on native option
34839                    if ($isliteNativeOptionChange) {
34840                        $optionLogParams = array(
34841                            'user_id' => $userData['User']['id'],
34842                            'platform' => Configure::read('platform.pclp'),
34843                            'status' => 3,//set to unsubscribe
34844                            'controller_name' => $this->request->params['controller'],
34845                            'action_name' => $this->request->params['action'],
34846                            'user_type' => 0, // user
34847                            'option_before' => 1,
34848                            'option_after' => '',
34849                            'option_before_name' => 'Native Unlimited Option',
34850                            'option_after_name' => '',
34851                            'option_type' => 1,
34852                            'payment_plan_id' => $paymentPlanId
34853                        );
34854
34855                        $_saveLog = ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
34856
34857                        if (!$_saveLog) {
34858                            $this->log(__METHOD__ . ' Failed to update option change. ' . json_encode($optionLogParams), $logFileName);
34859                            $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed to update user data', $optionLogParams);
34860                            $dataSource->rollback();
34861                            $dataSource->commit();
34862                            return ;
34863                        }
34864                    }
34865
34866                    # add log if change on callan option 
34867                    if ($isliteCallanOptionChange) {
34868
34869                        $optionLogParams = array(
34870                            'user_id' => $userId,
34871                            'platform' => Configure::read('platform.pclp'),
34872                            'status' => 3,//unsubscribe
34873                            'controller_name' => $this->request->params['controller'],
34874                            'action_name' => $this->request->params['action'],
34875                            'user_type' => 0, // user
34876                            'option_before' => 1,
34877                            'option_after' => '',
34878                            'option_before_name' => 'Callan Unlimited Option',
34879                            'option_after_name' => '',
34880                            'option_type' => 2,
34881                            'payment_plan_id' => $paymentPlanId
34882                        );
34883
34884                        $_saveLog = ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
34885
34886                        // rollback if confiscating points failed
34887                        if (!$_saveLog) {
34888                            $this->log(__METHOD__ . ' Failed to save user option change log. --> ' . json_encode($optionLogParams) . ' -- ' . json_encode($data), $logFileName);
34889                                    
34890                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save option log.', $optionLogParams);
34891                            $dataSource->rollback();
34892                            $dataSource->commit();
34893                            return ;
34894                        }
34895                    }
34896                }
34897                
34898
34899                // NC-7459 check previus user status, add coinbox challenge
34900                if (
34901                    isset($read['User']['payment_plan_id'])
34902                    && $read['User']['payment_plan_id'] == Configure::read('payment_plans.complimentary_plan')
34903                    && isset($read['User']['complimentary_code'])
34904                ) {
34905
34906                    // get complimentary coin award
34907                    $coinAward = $this->ComplimentaryCode->find('first', array(
34908                        'fields' => array('coin_award'),
34909                        'conditions' => array(
34910                            'ComplimentaryCode.code' => $read['User']['complimentary_code'],
34911                            'ComplimentaryCode.template_type !=' => 0 // // Free trial
34912                        )
34913                    ));
34914
34915                    if (
34916                        isset($coinAward['ComplimentaryCode']['coin_award'])
34917                        && $coinAward['ComplimentaryCode']['coin_award']
34918                    ) { // @TODO use common @note did not use CoinBox->addCoinReward because it will not succeed for unknown reason.
34919                        $coinboxSet = array(
34920                            'status' => 1,
34921                            'user_id' => $userData['User']['id'],
34922                            'teacher_id' => null,
34923                            'coin_event_id' => Configure::read('coin_box_event.complimentary'),
34924                            'coin' => $coinAward['ComplimentaryCode']['coin_award'],
34925                            'lesson_id' => NULL,
34926                            'expiration_date' => date('Y-m-d 23:59:59', strtotime('+59 days'))
34927                        );
34928                        $this->CoinBox->create();
34929                        $this->CoinBox->set($coinboxSet);
34930                        if (!$this->CoinBox->save()) {
34931                            CakeLog::debug('[debug_payment_proceed] complimentary coin award : ' . json_encode($saveUserArr));
34932                            $this->log(__METHOD__ . ' Failed adding complimentary coin award . ' . json_encode($saveUserArr) . ' -- ' . json_encode($data) . ' -- ' . json_encode($coinAward), $logFileName);
34933                            $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed adding complimentary coin award', $data, $coinboxSet);
34934                            $dataSource->rollback();
34935                            $dataSource->commit();
34936                            return ;
34937                        }
34938                    }
34939                }
34940                
34941                $memKey = 'family_reactivation_' . $data['sendid'] . '_' . $familyId;
34942                $familyReactivation = $this->memcache->get($memKey);
34943                // NC-3754 : add memo for reactivation parent user.
34944                if ($formType == Configure::read('payment_credit_family_monthly_payment') && !empty($read['User']['parent_id']) && $familyReactivation) {
34945                    $famRegist = false;
34946                    // delete memcache
34947                    $this->memcache->delete($memKey);
34948                    $this->User->clear();
34949                    if (!$userRead = $this->User->read(array('memo'), $data['sendid'])) {
34950                        $this->log(__METHOD__ . ' User id does not exist. ' . json_encode($data), $logFileName);
34951                        $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'User id does not exist', $data);
34952                        $dataSource->rollback();
34953                        $dataSource->commit();
34954                        return ;
34955                    }
34956
34957                    $this->User->set(array('memo' => date('Y/m/d H:i:s')." Family plan[User]: family id: " . $userData['User']['id'] . " reactivation \n" . $userRead['User']['memo']));
34958                    $this->User->validate = false;
34959                    if (!$this->User->save()) {
34960                        $this->log(__METHOD__ . ' Failed update user data. ' . json_encode($userRead) . ' -- ' . json_encode($data), $logFileName);
34961                        $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed update user data', $data, $userRead);
34962                        $dataSource->rollback();
34963                        $dataSource->commit();
34964                        return ;
34965                    }
34966                }
34967
34968                // NC-3754 
34969                // Proccess Family Plan
34970                if($famRegist && !$familyReactivation) {
34971                    // @param:  parent id. for memcache key.
34972                    $famPlanRes = $this->FamilyPlanList->processFamPlan($data['sendid'], $familyId, $data['sendpoint']);
34973                    if ($famPlanRes != "[OK]") {
34974                        $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], $famPlanRes, $data);
34975                        $dataSource->rollback();
34976                        $dataSource->commit();
34977                        return;
34978                    }
34979                }
34980
34981                // check if membership status was change
34982                if (isset($ptPaymentParams['statusBefore']) && isset($ptPaymentParams['statusAfter']) && isset($ptPaymentParams['platform'])) {
34983                    $currentUser = $this->User->find('first', array(
34984                        'fields' => array('User.parent_id', 'User.currency_code', 'User.payment_plan_id'),
34985                        'conditions' => array('User.id' => $userId),
34986                        'recursive' => -1
34987                    ));
34988                    $parentId = $currentUser['User']['parent_id'];
34989                    $is_cron = 0;
34990                    if (php_sapi_name() == 'cli' || $ptPaymentParams['logFileName'] == 'retry_monthly_payment'){
34991                        $is_cron = 1;
34992                    } 
34993                       $currency_after = $currentUser['User']['currency_code'];
34994                       $plan_after = $currentUser['User']['payment_plan_id'];
34995
34996                    $usclData = array(
34997                        'user_id' => $userId,
34998                        'platform' => $ptPaymentParams['platform'] ?? '',
34999                        'card_company_before' => $read['User']['card_company'],
35000                        'status_before' => $ptPaymentParams['statusBefore'],
35001                        'status_after' => $ptPaymentParams['statusAfter'],
35002                        'controller_name' => $this->request->params['controller'],
35003                        'action_name' => $this->request->params['action'],
35004                        'parent_id' => $parentId,
35005                        'is_cron' => $is_cron,
35006                        'currency_before' => $currency_before,
35007                        'currency_after' => $currency_after,
35008                        'payment_plan_id_before' => $plan_before,
35009                        'payment_plan_id_after' => $plan_after,
35010                        'default_appreciation_flg' => $appreciationFlg,
35011                        'default_appreciation_amount' => $tipAmount
35012                    );
35013                    // save user change membership status
35014                    if (!$this->UserStatusChangeLog->saveLog($usclData)) {
35015                        $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'Unable to update status change log', $usclData);
35016                        $dataSource->rollback();
35017                        $dataSource->commit();
35018                        return;
35019                    }
35020                }
35021
35022                # check if user is temporary
35023                if (
35024                    ($userData['User']['status'] == 0 && $formType == Configure::read('payment_credit_authentication')) || 
35025                    ($userData['User']['status'] == 0 && $formType == Configure::read('payment_lite_credit_free') )
35026                ) {
35027                    # update user's status after step 4
35028                    $this->User->validate = array();
35029                    if (!$this->User->read(null, $userData['User']['id'])) {
35030                        $this->log(__METHOD__ . ' User id does not exist. ' . json_encode($userData), $logFileName);
35031                        $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'User id does not exist', $userData);
35032                        $dataSource->rollback();
35033                        $dataSource->commit();
35034                        return ;
35035                    }
35036                    $this->User->set('status', 1);
35037                    if (!$this->User->save()) {
35038                        $this->log(__METHOD__ . ' Failed update user status to 1. ' . json_encode($data), $logFileName);
35039                        $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed update user status to 1', $data);
35040                        $dataSource->rollback();
35041                        $dataSource->commit();
35042                        return ;
35043                    }
35044                }
35045
35046                // NC-7779 : check if user has chivox monthly test taken for the current month, and monthly_speaking_attended_flg ON,
35047                // turn Off the flag if users has not yet taken the exam for the current month.
35048                // @TODO check query
35049                if (
35050                    isset($userData['User']['monthly_speaking_attended_flg']) && isset($userData['User']['monthly_speaking_business_attended_flg'])
35051                    && ($userData['User']['monthly_speaking_attended_flg'] == 1 || $userData['User']['monthly_speaking_business_attended_flg'] == 1)
35052                ) {
35053
35054                    // check chivox monthly
35055                    $paymentPlanIdsForChivoxMonthly = Configure::read('chivox.monthly.user_payment_plan_cantake_exam');
35056                    if (in_array($paymentPlanId, $paymentPlanIdsForChivoxMonthly)) {
35057
35058                        // load model
35059                        $this->loadModel("UsersChivoxMonthlyTest");
35060                        $userTestMonthFlagParams['user_id'] = $userData['User']['id'];
35061                        $userTestMonthFlag = $this->UsersChivoxMonthlyTest->checkUserCurrentMonthExam($userTestMonthFlagParams);
35062
35063                        $monthly_speaking_attended_flg = Configure::read('chivox.test_data_test_type.daily'); // test_type daily speaking 0
35064                        $monthly_speaking_business_attended_flg = Configure::read('chivox.test_data_test_type.business'); // test_type business 1
35065                        $fieldsToUpdate = array();
35066
35067                        // if user hat not yet taken the exam for current month
35068                        if (!in_array($monthly_speaking_attended_flg, $userTestMonthFlag)) {
35069                            $fieldsToUpdate['monthly_speaking_attended_flg'] = 0;
35070                        }
35071                        if (!in_array($monthly_speaking_business_attended_flg, $userTestMonthFlag)) {
35072                            $fieldsToUpdate['monthly_speaking_business_attended_flg'] = 0;
35073                        }
35074
35075                        if ($fieldsToUpdate) {
35076                            $this->User->validate = array();
35077                            if (!$this->User->read(null, $userData['User']['id'])) {
35078                                $this->log(__METHOD__ . ' [NC-7779] User id does not exist. ' . json_encode($userData), $logFileName);
35079                                $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'User id does not exist', $userData);
35080                                $dataSource->rollback();
35081                                $dataSource->commit();
35082                                return ;
35083                            }
35084                            $this->User->set($fieldsToUpdate);
35085                            if (!$this->User->save()) {
35086                                $this->log(__METHOD__ . ' [NC-7779] Failed update user monthly_speaking_attended_flg or monthly_speaking_business_attended_flg to 0. ' . json_encode($data), $logFileName);
35087                                $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed update user monthly_speaking_attended_flg to 0', $data);
35088                                $dataSource->rollback();
35089                                $dataSource->commit();
35090                                return ;
35091                            }
35092                        }
35093                    }
35094                }
35095            }
35096
35097            $annualDiscountOption = isset($ptPaymentParams['annualDiscountOption']) ? $ptPaymentParams['annualDiscountOption'] : [];
35098            // if user cancel annual discount option
35099            if (
35100                $annualDiscountOption &&
35101                isset($annualDiscountOption['cancellation_fee']) &&
35102                $formType == Configure::read('payment_halfway_termination_of_annual_discount_option')
35103            ) {
35104                $doshData = [
35105                    'user_id' => $userId,
35106                    'discount_option_term_id' => $annualDiscountOption['discount_option_term_id'],
35107                    'discount_option_id' => $annualDiscountOption['discount_option_id'],
35108                    'discount_option_price_id' => $annualDiscountOption['discount_option_price_id'],
35109                    'payment_id' => $paymentSaveID,
35110                    'event' => $annualDiscountOption['dosh_event'],
35111                    'amount' => $annualDiscountOption['cancellation_fee'],
35112                    'currency_code' => $currencyCode,
35113                    'type' => $annualDiscountOption['dosh_type'],
35114                    'status' => $annualDiscountOption['dosh_status'],
35115                    'settlement_status' => 1 // success
35116                ];
35117
35118                // create discount option settlement history
35119                if (!$res = $this->DiscountOptionsSettlementHistory->createHistory($doshData)) {
35120                    $this->log(__METHOD__ . ' Failed to create discount option settlement history. ' . json_encode($doshData), $logFileName);
35121                    $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to create discount option settlement history. ', $doshData);
35122                    $dataSource->rollback();
35123                    $dataSource->commit();
35124                    return ;
35125                }
35126
35127                // stop user annual discount option term
35128                if (!$this->UserDiscountOptionsTerm->stopTerm(['userId' => $userId])) {
35129                    $this->log(__METHOD__ . ' Failed to stop annual discount option term. ' . json_encode(['userId' => $userId]), $logFileName);
35130                    $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to stop annual discount option term.', ['userId' => $userId]);
35131                    $dataSource->rollback();
35132                    $dataSource->commit();
35133                    return ;
35134                }
35135
35136                // update user memo
35137                $memo = date('Y/m/d H:i') . " 年間割引オプション解約\n" . $userData['User']['memo'];
35138                if (!$this->User->updateUserById(['userData' => ['memo' => $memo], 'id' => $userId])) {
35139                    $this->log(__METHOD__ . ' Failed to update user memo. ' . json_encode($memo) . ' id: ' . json_encode($userId), $logFileName);
35140                    $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to stop annual discount option term.', [$memo]);
35141                    $dataSource->rollback();
35142                    $dataSource->commit();
35143                    return ;
35144                }
35145                
35146                $adoLogParams = [
35147                    'user_id' => $userId,
35148                    'platform' => $platform,
35149                    'status' => 1, // subscribe
35150                    'controller_name' => $this->request->params['controller'],
35151                    'action_name' => $this->request->params['action'],
35152                    'user_type' => 0, // normal user
35153                    'option_before' => 1,
35154                    'option_after' => '',
35155                    'option_before_name' => 'Annual Discount Option',
35156                    'option_after_name' => '',
35157                    'option_type' => 3, // annual discount option
35158                    'payment_plan_id' => $paymentPlanId
35159                ];
35160
35161                if (!$this->UserOptionChangeLog->saveOptionChangeLog($adoLogParams)) {
35162                    $this->log(__METHOD__ . ' Failed to update option change. ' . json_encode($adoLogParams), $logFileName);
35163                    $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'Failed to update user data', $adoLogParams);
35164                    $dataSource->rollback();
35165                    $dataSource->commit();
35166                    return ;
35167                }
35168            }
35169
35170            // if payment was saved, and form type belongs to textbook purchase,
35171            // update textbook_sales table, insert payment_id
35172            if ($formType == Configure::read('payment_credit_textbook_purchase')) {
35173                // set textbook sales info
35174                $textbookSales = $this->TextbookSale->find('first', array(
35175                    'conditions' => array(
35176                        'TextbookSale.sales_code' => $ptPassword
35177                    ),
35178                    'recursive' => -1
35179                ));
35180                
35181                // if has textbook sales, update payment_id
35182                if ($textbookSales) {
35183                    $this->TextbookSale->clear();
35184                    if (!$this->TextbookSale->read(null, $textbookSales['TextbookSale']['id'])) {
35185                        $this->log(__METHOD__ . ' Textbook sales id does not exist. ' . json_encode($textbookSales), $logFileName);
35186                        $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'Textbook sales id does not exist', $textbookSales);
35187                        $dataSource->rollback();
35188                        $dataSource->commit();
35189                        return ;
35190                    }
35191                    $this->TextbookSale->set('payment_id', $this->Payment->id);
35192                    $this->TextbookSale->set('payment_status', 1);
35193                    if (!$this->TextbookSale->save()) {
35194                        $this->log(__METHOD__ . ' Failed update textbook sales payment status to 1. ' . json_encode($textbookSales), $logFileName);
35195                        $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'Failed update textbook sales payment status to 1', $textbookSales);
35196                        $dataSource->rollback();
35197                        $dataSource->commit();
35198                        return ;
35199                    }
35200                }
35201            }
35202
35203            // [STRIPE] check if receivable payment sent was either
35204            // receivable payment, monthly payment, force settlement, or retry payment
35205            // if yes, set receivable payments to "received"
35206            if (
35207                in_array($formType, array(
35208                    Configure::read('payment_credit_appreciation_receivable'),
35209                    Configure::read('payment_credit_receivable'),
35210                    Configure::read('payment_credit_monthly_payment'),
35211                    Configure::read('payment_credit_force_charge'),
35212                    Configure::read('payment_credit_retry'),
35213                    Configure::read('payment_credit_family_monthly_payment'),
35214                    Configure::read('payment_lite_credit_monthly_payment'),
35215                    Configure::read('payment_lite_credit_paid'),
35216                    Configure::read('payment_lite_plan_downgrade'),
35217                    Configure::read('payment_lite_plan_upgrade'),
35218                    Configure::read('payment_credit_change')
35219                ))
35220            ) {
35221                // get current payment_id
35222                $paymentID = $this->Payment->id;
35223
35224                // create new payment receivable
35225                if ($formType != Configure::read('payment_credit_receivable') && $receivablePayment) {
35226                    // set payment id
35227                    $data["payment_id"] = $paymentID;
35228
35229                    $paymentData = array(
35230                        'user_id' => $userId,
35231                        'amount' => $receivablePayment,
35232                        'status' => 1,
35233                        'type_id' => 1,
35234                        'reference_id' => $referenceId,
35235                        'card_company' => $card_company,
35236                        'param1' => json_encode($data),
35237                        'form_type' => Configure::read('payment_credit_receivable'),
35238                        'ordd' => $data["ordd"],
35239                        'currency_code' => $currencyCode, // set currency id to jpy
35240                        'transaction_code' => $paymentHash,
35241                        'price_id' => $priceId,
35242                        'payment_id' => $paymentPlanId,
35243                        'payment_type' => $paymentType,
35244                        'discounted_amount' => 0
35245                    );
35246
35247                    // create new payment
35248                    $this->Payment->clear();
35249                    $this->Payment->create();
35250                    $this->Payment->set($paymentData);
35251                    if (!$this->Payment->save()) {
35252                        $this->log(__METHOD__ . ' Failed to save payment data' . json_encode($paymentData), $logFileName);
35253                        $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data', $paymentData);
35254                        $dataSource->rollback();
35255                        $dataSource->commit();
35256                        return ;
35257                    }
35258
35259                    //update/add user`s settlement amount
35260                    $this->User->updateUserPayments($paymentData);
35261                    // set payment_id
35262                    $paymentID = $this->Payment->id;
35263
35264                }
35265
35266                // set payment receivable statuses to 2 - received
35267                $this->PaymentReceivable->updateReceivableReservationPayment(
35268                    $userData['User']['id'], 
35269                    array(
35270                        'status' => 2,
35271                        'payment_id' => $paymentID,
35272                        'payment_collection_date' => date("Y-m-d H:i:s"),
35273                        'card_company' => $card_company,
35274                        'payment_plan_id' => $paymentPlanId,
35275                        'membership_type_index' => $membershipStatusIndex
35276                    ),
35277                    array(
35278                        'PaymentReceivable.user_id' => $userData['User']['id'],
35279                        'PaymentReceivable.status' => 0,
35280                        'PaymentReceivable.payment_element_type' => 1,
35281                        'PaymentReceivable.created <=' => $cronDateRun
35282                    )
35283                );
35284
35285                // debug log
35286                $this->log("[STRIPEPAY_RECEIVABLE] kickback was recieved -> " . json_encode($data), $logFileName);
35287
35288                // create new payment for appreciation receivable
35289                if ($formType != Configure::read('payment_credit_appreciation_receivable') && $appreciationReceivable > 0) {
35290                    // set payment id
35291                    $data["payment_id"] = $paymentID;
35292                    //reset payment data
35293                    $paymentData = array();
35294
35295                    //set payment data
35296                    $paymentData = array(
35297                        'user_id' => $userId,
35298                        'amount' => $appreciationReceivable,
35299                        'status' => 1,
35300                        'type_id' => 1,
35301                        'reference_id' => $referenceId,
35302                        'card_company' => $card_company,
35303                        'param1' => json_encode($data),
35304                        'form_type' => Configure::read('appreciation_data.payment_form_type'),
35305                        'ordd' => $data["ordd"],
35306                        'currency_code' => $currencyCode, // set currency id to jpy
35307                        'transaction_code' => $paymentHash,
35308                        'price_id' => $priceId,
35309                        'payment_id' => $paymentPlanId,
35310                        'payment_type' => $paymentType,
35311                        'discounted_amount' => 0
35312                    );
35313
35314                    // create new payment
35315                    $this->Payment->clear();
35316                    $this->Payment->create();
35317                    $this->Payment->set($paymentData);
35318                    if (!$this->Payment->save()) {
35319                        $this->log(__METHOD__ . ' Failed to save appreciationReceivable payment data' . json_encode($paymentData), $logFileName);
35320                        $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save appreciationReceivable payment data', $paymentData);
35321                        $dataSource->rollback();
35322                        $dataSource->commit();
35323                        return ;
35324                    }
35325                    //update/add user`s settlement amount
35326                    $this->User->updateUserPayments($paymentData);
35327                    // set payment_id
35328                    $paymentID = $this->Payment->id;
35329
35330                }
35331
35332                // set payment receivable for appreciation statuses to 2 - received
35333                $this->PaymentReceivable->updateReceivableReservationPayment(
35334                    $userData['User']['id'], 
35335                    array(
35336                        'status' => 2,
35337                        'payment_id' => $paymentID,
35338                        'payment_collection_date' => date("Y-m-d H:i:s"),
35339                        'card_company' => $card_company,
35340                        'payment_plan_id' => $paymentPlanId,
35341                        'membership_type_index' => $membershipStatusIndex
35342                    ),
35343                    array(
35344                        'PaymentReceivable.user_id' => $userData['User']['id'],
35345                        'PaymentReceivable.status' => 0,
35346                        'PaymentReceivable.payment_element_type' => Configure::read('appreciation_data.payment_element_type'),
35347                        'PaymentReceivable.created <=' => $cronDateRun
35348                    )
35349                );
35350
35351                // debug log
35352                $this->log("[STIPEPAY_APPRECIATION_RECEIVABLE] kickback was recieved -> " . json_encode($data), $logFileName);
35353
35354                // create new payment for live lesson receivable
35355                if ($formType != Configure::read('payment_live_lesson_receivable') && $liveLessonReceivable) {
35356                    // set payment id
35357                    $data["payment_id"] = $paymentID;
35358
35359                    $paymentData = array(
35360                        'user_id' => $userId,
35361                        'amount' => $liveLessonReceivable,
35362                        'status' => 1,
35363                        'type_id' => 1,
35364                        'reference_id' => $referenceId,
35365                        'card_company' => $card_company,
35366                        'param1' => json_encode($data),
35367                        'form_type' => Configure::read('payment_live_lesson_receivable'),
35368                        'ordd' => $data["ordd"],
35369                        'currency_code' => $currencyCode, // set currency id to jpy
35370                        'transaction_code' => $paymentHash,
35371                        'price_id' => $priceId,
35372                        'payment_id' => $paymentPlanId,
35373                        'payment_type' => $paymentType,
35374                        'discounted_amount' => 0
35375                    );
35376
35377                    // create new payment
35378                    $this->Payment->clear();
35379                    $this->Payment->create();
35380                    $this->Payment->set($paymentData);
35381                    if (!$this->Payment->save()) {
35382                        $this->log(__METHOD__ . ' Failed to save payment data' . json_encode($paymentData), $logFileName);
35383                        $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data', $paymentData);
35384                        $dataSource->rollback();
35385                        $dataSource->commit();
35386                        return ;
35387                    }
35388                    //update/add user`s settlement amount
35389                    $this->User->updateUserPayments($paymentData);
35390                    // set payment_id
35391                    $paymentID = $this->Payment->id;
35392                }
35393
35394                // set payment receivable for live lesson statuses to 2 - received
35395                $this->PaymentReceivable->updateReceivableReservationPayment(
35396                    $userData['User']['id'], 
35397                    array(
35398                        'status' => 2,
35399                        'payment_id' => $paymentID,
35400                        'payment_collection_date' => date("Y-m-d H:i:s"),
35401                        'card_company' => $card_company,
35402                        'payment_plan_id' => $paymentPlanId,
35403                        'membership_type_index' => $membershipStatusIndex
35404                    ),
35405                    array(
35406                        'PaymentReceivable.user_id' => $userData['User']['id'],
35407                        'PaymentReceivable.status' => 0,
35408                        'PaymentReceivable.payment_element_type' => Configure::read('payment_element_type.live'),
35409                        'PaymentReceivable.created <=' => $cronDateRun
35410                    )
35411                );
35412                
35413                // debug log
35414                $this->log("[STRIPEPAY_LIVE_RECEIVABLE] kickback was recieved -> " . json_encode($data), $logFileName);                
35415
35416            }
35417
35418            // NJ-63985
35419            if (!empty($ptPaymentParams['monthlyDiscount']) && !empty($ptPaymentParams['monthly_grp_id'])) {
35420                $requestCouponConfirmData = array(
35421                    'grpId' => $ptPaymentParams['monthly_grp_id'],
35422                    'paymentId' => $paymentSaveID
35423                );
35424
35425                $result_confirm = $this->UsersCouponV1->performCouponConfirm($requestCouponConfirmData);
35426
35427                if (!$result_confirm) {
35428                    $this->log(__METHOD__ . ' Failed to update used coupons.' . json_encode($ucData), $logFileName);
35429                    $this->log(__METHOD__ . ' Failed to update used coupons.' . json_encode($ucData), 'error');
35430                    $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update used coupons.', $ucData);
35431                    $dataSource->rollback();
35432                    $dataSource->commit();
35433                    return ;
35434                }
35435            }
35436
35437            // NC-7029: CHECK REFERRAL USER
35438            if (
35439                in_array($formType, array(
35440                    Configure::read('payment_credit_monthly_payment'),
35441                    Configure::read('payment_credit_force_charge'),
35442                    Configure::read('payment_credit_retry'),
35443                    Configure::read('payment_credit_authentication'),
35444                    Configure::read('payment_credit_family_monthly_payment'),
35445                    Configure::read('payment_lite_credit_monthly_payment'),
35446                    Configure::read('payment_lite_credit_paid')
35447                ))
35448            ) {
35449                $ruData = array(
35450                    'referee_id' => $userData['User']['id'],
35451                    'payment_plan_id' => $newYear95percentOffCampaign ? Configure::read('payment_plans.free_trial') : $paymentPlanId,
35452                    'currency_code' => $userData['User']['currency_code'],
35453                    'logFileName' => $logFileName,
35454                    'form_type' => $newYear95percentOffCampaign ? Configure::read('payment_credit_authentication') : $formType
35455                );
35456
35457                $couponReferredData = $this->UsersReferral->checkReferredUser($ruData);
35458                if (isset($couponReferredData['error']) && $couponReferredData['error']) {
35459                    $this->log(__METHOD__ . ' Failed to update users referral event flg.' . json_encode($ruData), $logFileName);
35460                    $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update users referral event flg.', $ruData);
35461                    $dataSource->rollback();
35462                    $dataSource->commit();
35463                    return ;
35464                }
35465
35466                $couponMailId = Configure::read('site_in_mail.coupon_mail_template_id');
35467
35468                // send coupon mail to referee
35469                if (isset($couponReferredData['sendMailToReferee']) && $couponReferredData['sendMailToReferee']) {
35470                    $refereeData = array(
35471                        'id' => $userData['User']['id'],
35472                        'email' => $userData['User']['email'],
35473                        'native_language2' => $userData['User']['native_language2'],
35474                        'hash' => $userData['User']['hash'],
35475                        'refereeName' => $userData['User']['nickname'],
35476                        'referrerName' => $couponReferredData['referrerName'],
35477                        'couponAmount' => $couponReferredData['refereeSaveAmount'],
35478                        'couponUpdatedTotal' => $couponReferredData['refereeUpdatedTotal']
35479                    );
35480
35481                    // send mail to referee
35482                    myMailer::sendTemplateMail($couponMailId, $userData['User']['email'], $refereeData, array(), 'User');
35483                }
35484
35485                // send coupon mail to referer
35486                if (isset($couponReferredData['sendMailToReferer']) && $couponReferredData['sendMailToReferer']) {
35487                    $referrerData = array(
35488                        'id' => $couponReferredData['referrerId'],
35489                        'email' => $couponReferredData['referrerEmail'],
35490                        'native_language2' => $couponReferredData['nativeLanguage2'],
35491                        'hash' => $couponReferredData['referrerHash'],
35492                        'refereeName' => $userData['User']['nickname'],
35493                        'referrerName' => $couponReferredData['referrerName'],
35494                        'couponAmount' => $couponReferredData['refererSaveAmount'],
35495                        'couponUpdatedTotal' => $couponReferredData['refererUpdatedTotal']
35496                    );
35497
35498                    // send mail to referrer
35499                    myMailer::sendTemplateMail($couponMailId, $couponReferredData['referrerEmail'], $referrerData, array(), 'User');
35500                }
35501
35502                
35503                if ( //Amazon gift campaign
35504                    in_array($formType, array(
35505                        Configure::read('payment_credit_force_charge'),
35506                        Configure::read('payment_credit_authentication')
35507                    ))
35508                ) {
35509                    ClassRegistry::init('CampaignSettingTable')->amazonGift(array('user_id' => $userData['User']['id'], 'type' => 1));
35510                }
35511            }
35512                    
35513            // NJ-47740
35514            $getCouponDiscounDetail = PaymentTable::getCouponDiscountRequestDetail($ptPaymentParams, 'native');
35515            $nativeOptionDiscount = !empty($getCouponDiscounDetail['discounted_amount']) ? $getCouponDiscounDetail['discounted_amount'] : 0;
35516            $nativeCouponRequestId = !empty($getCouponDiscounDetail['coupon_request_id']) ? $getCouponDiscounDetail['coupon_request_id'] : null;
35517            // if has native speaker payment
35518            if (
35519                isset($ptPaymentParams['nativeOptionPayment']) && ($ptPaymentParams['nativeOptionPayment'] > 0 || $nativeOptionDiscount > 0)
35520                && in_array($ptPaymentParams['formType'], array(Configure::read('payment_credit_monthly_payment'), Configure::read('payment_credit_family_monthly_payment')))
35521            ) {
35522                $nspFormType = Configure::read('payment_native_option_monthly_payment');
35523                if (isset($ptPaymentParams['nativeOptionJoin']) && $ptPaymentParams['nativeOptionJoin']) {
35524                    $nspFormType = Configure::read('payment_native_option_join');
35525                }
35526                
35527                // check if family plan
35528                if ($familyId) {
35529                    // change reference id to parent id
35530                    $referenceId = isset($data['sendid']) ? $data['sendid'] : 0;
35531                } else {
35532                    $referenceId = $userId;
35533                }
35534
35535                $paymentData = array(
35536                    'user_id' => $userId,
35537                    'amount' => $ptPaymentParams['nativeOptionPayment'],
35538                    'status' => 1,
35539                    'type_id' => 1,
35540                    'reference_id' => $referenceId,
35541                    'payment_transaction_password' => $ptPassword,
35542                    'card_company' => $card_company,
35543                    'param1' => json_encode($data),
35544                    'form_type' => $nspFormType,
35545                    'ordd' => $data["ordd"],
35546                    'currency_code' => $currencyCode,
35547                    'transaction_code' => $paymentHash,
35548                    'price_id' => $priceId,
35549                    'payment_id' => $paymentPlanId,
35550                    'payment_type' => Configure::read('payment_types.native_option')
35551                );
35552
35553                // NJ-47740
35554                $paymentData['discounted_amount'] = $nativeOptionDiscount;
35555                $paymentData['coupon_request_id'] = $nativeCouponRequestId;
35556
35557                // create new payment
35558                $this->Payment->clear();
35559                $this->Payment->create();
35560                $this->Payment->set($paymentData);
35561                if (!$this->Payment->save()) {
35562                    $this->log(__METHOD__ . ' Failed to save payment data' . json_encode($paymentData), $logFileName);
35563                    $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data', $paymentData);
35564                    $dataSource->rollback();
35565                    return ;
35566                }
35567                
35568                //update/add user`s settlement amount
35569                $this->User->updateUserPayments($paymentData);
35570
35571                // NJ-47740
35572                if (!empty($paymentData['coupon_request_id']) && $paymentData['discounted_amount'] > 0) {
35573                    // confirm coupon use request for native discount
35574                    $requestCouponConfirmData = array(
35575                        'grpId' => $paymentData['coupon_request_id'],
35576                        'paymentId' => $this->Payment->id
35577                    );
35578                    $result_confirm = $this->UsersCouponV1->performCouponConfirm($requestCouponConfirmData);
35579                    
35580                    if (!$result_confirm) {
35581                        $this->log(__METHOD__ . ' Failed to confirm native coupon use request. ' . json_encode($requestCouponConfirmData) . ' -- ' . json_encode($data), $logFileName);
35582                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to confirm native coupon use request', $data, $requestCouponConfirmData);
35583                        return ;
35584                    }
35585                }
35586                // NJ-47740 end
35587                
35588                // update payment details
35589                $updatePaymentDetailParams = array(
35590                    'currencyCode' => $paymentData['currency_code'],
35591                    'formType' => $paymentData['form_type'],
35592                    'paymentType' => $paymentData['payment_type'],
35593                    'amount' => $paymentData['amount'],
35594                    'discounted_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0,
35595                    'familyId' => $familyId,
35596                    'cronDateRun' => $cronDateRun,
35597                    'priceId' => $paymentData['price_id'],
35598                    'paymentPlanId' => $paymentData['payment_id'],
35599                    'user_id' => $paymentData['user_id'],
35600                    'coupon_use_request_id' => isset($paymentData['coupon_request_id']) ? $paymentData['coupon_request_id'] : null,
35601                    'coupon_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0
35602                );
35603                
35604                $updatePaymentDetail = array(
35605                    'id' => $ptId,
35606                    'fields' => array(
35607                        'payment_details' => $updatePaymentDetailParams
35608                    )
35609                );
35610
35611                if (!$this->PaymentTransaction->updateWPPaymentTransaction($updatePaymentDetail)) {
35612                    $this->log(__METHOD__ . ' Failed to update payment details. ' . json_encode($updatePaymentDetail), $logFileName);
35613                }
35614            }
35615
35616            // if has callan option payment
35617            // NJ-47740
35618            $getCouponDiscounDetail = PaymentTable::getCouponDiscountRequestDetail($ptPaymentParams, 'callan');
35619            $callanOptionDiscount = !empty($getCouponDiscounDetail['discounted_amount']) ? $getCouponDiscounDetail['discounted_amount'] : 0;
35620            $callanCouponRequestId = !empty($getCouponDiscounDetail['coupon_request_id']) ? $getCouponDiscounDetail['coupon_request_id'] : null;
35621            // if has callan option payment
35622            if (
35623                isset($ptPaymentParams['callanOptionPayment']) && ($ptPaymentParams['callanOptionPayment'] > 0 || $callanOptionDiscount > 0)
35624                && in_array($ptPaymentParams['formType'], array(Configure::read('payment_credit_monthly_payment'), Configure::read('payment_credit_family_monthly_payment')))
35625            ) {
35626                $nspFormType = Configure::read('payment_callan_option_monthly_payment');
35627                if (isset($ptPaymentParams['callanOptionJoin']) && $ptPaymentParams['callanOptionJoin']) {
35628                    $nspFormType = Configure::read('payment_callan_option_join');
35629                }
35630                
35631                // check if family plan
35632                if ($familyId) {
35633                    // change reference id to parent id
35634                    $referenceId = isset($data['sendid']) ? $data['sendid'] : 0;
35635                } else {
35636                    $referenceId = $userId;
35637                }
35638
35639                $paymentData = array(
35640                    'user_id' => $userId,
35641                    'amount' => $ptPaymentParams['callanOptionPayment'],
35642                    'status' => 1,
35643                    'type_id' => 1,
35644                    'reference_id' => $referenceId,
35645                    'payment_transaction_password' => $ptPassword,
35646                    'card_company' => $card_company,
35647                    'param1' => json_encode($data),
35648                    'form_type' => $nspFormType,
35649                    'ordd' => $data["ordd"],
35650                    'currency_code' => $currencyCode,
35651                    'transaction_code' => $paymentHash,
35652                    'price_id' => $priceId,
35653                    'payment_id' => $paymentPlanId,
35654                    'payment_type' => Configure::read('payment_types.callan_option')
35655                );
35656                
35657                // NJ-47740
35658                $paymentData['discounted_amount'] = $callanOptionDiscount;
35659                $paymentData['coupon_request_id'] = $callanCouponRequestId;
35660
35661                // create new payment
35662                $this->Payment->clear();
35663                $this->Payment->create();
35664                $this->Payment->set($paymentData);
35665                if (!$this->Payment->save()) {
35666                    $this->log(__METHOD__ . ' Failed to save payment data' . json_encode($paymentData), $logFileName);
35667                    $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data', $paymentData);
35668                    $dataSource->rollback();
35669                    return ;
35670                }
35671                
35672                //update/add user`s settlement amount
35673                $this->User->updateUserPayments($paymentData);
35674
35675                // NJ-47740
35676                if (!empty($paymentData['coupon_request_id']) && $paymentData['discounted_amount'] > 0) {
35677                    // confirm coupon use request for callan discount
35678                    $requestCouponConfirmData = array(
35679                        'grpId' => $paymentData['coupon_request_id'],
35680                        'paymentId' => $this->Payment->id
35681                    );
35682                    $result_confirm = $this->UsersCouponV1->performCouponConfirm($requestCouponConfirmData);
35683
35684                    if (!$result_confirm) {
35685                        $this->log(__METHOD__ . ' Failed to confirm callan coupon use request. ' . json_encode($requestCouponConfirmData) . ' -- ' . json_encode($data), $logFileName);
35686                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to confirm callan coupon use request', $data, $requestCouponConfirmData);
35687                        return;
35688                    }
35689                }
35690                // NJ-47740 end
35691                
35692                // update payment details
35693                $updatePaymentDetailParams = array(
35694                    'currencyCode' => $paymentData['currency_code'],
35695                    'formType' => $paymentData['form_type'],
35696                    'paymentType' => $paymentData['payment_type'],
35697                    'amount' => $paymentData['amount'],
35698                    'discounted_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0,
35699                    'familyId' => $familyId,
35700                    'cronDateRun' => $cronDateRun,
35701                    'priceId' => $paymentData['price_id'],
35702                    'paymentPlanId' => $paymentData['payment_id'],
35703                    'user_id' => $paymentData['user_id'],
35704                    'coupon_use_request_id' => isset($paymentData['coupon_request_id']) ? $paymentData['coupon_request_id'] : null,
35705                    'coupon_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0
35706                );
35707                
35708                $updatePaymentDetail = array(
35709                    'id' => $ptId,
35710                    'fields' => array(
35711                        'payment_details' => $updatePaymentDetailParams
35712                    )
35713                );
35714
35715                if (!$this->PaymentTransaction->updateWPPaymentTransaction($updatePaymentDetail)) {
35716                    $this->log(__METHOD__ . ' Failed to update payment details. ' . json_encode($updatePaymentDetail), $logFileName);
35717                }
35718            }
35719            
35720            // activate the user native option (new, resume, and monthly payment)
35721            if (isset($ptPaymentParams['nativeOptionPayment']) && ($ptPaymentParams['nativeOptionPayment'] > 0 || $nativeOptionDiscount > 0)) { 
35722
35723                $this->log(__METHOD__ . ' NJ-2388 debug Payment Transaction Data: ' . json_encode($ptData), 'native_option_debug');
35724
35725                // - option process data
35726                $optionProcessData = array(
35727                    'user_id' => $userId,
35728                    'type' => 'on',
35729                    'option_type' => Configure::read('native_speaker.options.all_you_can_eat')
35730                );
35731
35732                $this->User->userNativeOptionProcess($optionProcessData);
35733
35734                //NJ-2814 add logs
35735                if (isset($ptPaymentParams['nativeOptionJoin']) && $ptPaymentParams['nativeOptionJoin']) {
35736                    $nativeStatus = 1; // subscribed
35737                    $statusBefore = '';
35738                } else {
35739                    $nativeStatus = 2; // Monthly Continue
35740                    $statusBefore = 1;
35741                }
35742
35743                $optionAfterName = 'Native Unlimited Option';
35744
35745                $optionLogParams = array(
35746                    'user_id' => $userId,
35747                    'platform' => $ptPaymentParams['platform'],
35748                    'status' => $nativeStatus,
35749                    'controller_name' => $this->request->params['controller'],
35750                    'action_name' => $this->request->params['action'],
35751                    'user_type' => 0, // user
35752                    'option_before' => $statusBefore,
35753                    'option_after' => 1,
35754                    'option_before_name' => '',
35755                    'option_after_name' => $optionAfterName,
35756                    'option_type' => 1,
35757                    'payment_plan_id' => $paymentPlanId
35758                );
35759
35760                ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
35761
35762                // - save registration status step
35763                $stepKey = Configure::read('registration_steps.user_info_entry');
35764                $this->saveStep($userId, $stepKey);
35765            }
35766
35767            // activate the user native option (new, resume, and monthly payment)
35768            if (isset($ptPaymentParams['callanOptionPayment']) && ($ptPaymentParams['callanOptionPayment'] > 0 || $callanOptionDiscount > 0)) { 
35769
35770                $this->log(__METHOD__ . ' NJ-2388 debug Payment Transaction Data: ' . json_encode($ptData), 'native_option_debug');
35771
35772                // - option process data
35773                $optionProcessData = array(
35774                    'user_id' => $userId,
35775                    'type' => 'on',
35776                    'option_type' => Configure::read('callan_unlimited.options.callan_unlimited_option')
35777                );
35778
35779                $this->User->userNativeOptionProcess($optionProcessData);
35780
35781                //NJ-2814 add logs
35782                if (isset($ptPaymentParams['callanOptionJoin']) && $ptPaymentParams['callanOptionJoin']) {
35783                    $nativeStatus = 1; // subscribed
35784                    $statusBefore = '';
35785                } else {
35786                    $nativeStatus = 2; // Monthly Continue
35787                    $statusBefore = 1;
35788                }
35789                $optionAfterName = 'Callan Unlimited Option';
35790                $optionLogParams = array(
35791                    'user_id' => $userId,
35792                    'platform' => $ptPaymentParams['platform'],
35793                    'status' => $nativeStatus,
35794                    'controller_name' => $this->request->params['controller'],
35795                    'action_name' => $this->request->params['action'],
35796                    'user_type' => 0, // user
35797                    'option_before' => $statusBefore,
35798                    'option_after' => 1,
35799                    'option_before_name' => '',
35800                    'option_after_name' => $optionAfterName,
35801                    'option_type' => 2,
35802                    'payment_plan_id' => $paymentPlanId
35803                );
35804
35805                ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
35806            }
35807
35808            // if parent user update children's card company
35809            if ($formType == Configure::read('payment_credit_change')) {
35810                $childList = $this->User->getChildId($userId);
35811
35812                // check if user is parent
35813                if (!empty($childList)) {
35814                    foreach ($childList as $childId) {
35815                        $this->User->clear();
35816                        $updateCCArr = array('card_company' => $card_company);
35817
35818                        //Update also child card exp date same with parent
35819                        if (isset($ptPaymentParams['cardExpirationDate'])) {
35820                            $updateCCArr['card_expiration_date'] = $ptPaymentParams['cardExpirationDate'];
35821                        }
35822
35823                        if (!$this->User->read(array_keys($updateCCArr), $childId)) {
35824                            $this->log(__METHOD__ . ' child id does not exist. ' . json_encode($updateCCArr) . ' parent id --> ' . json_encode($userId), $logFileName);
35825                            $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'child id does not exist.', $updateCCArr);
35826                            $dataSource->rollback();
35827                            $dataSource->commit();
35828                            return ;
35829                        }
35830
35831                        $this->User->set($updateCCArr);
35832                        if (!$this->User->save()) {
35833                            $this->log(__METHOD__ . ' failed to update child card company. ' . json_encode($updateCCArr) . ' parent id --> ' . json_encode($userId), $logFileName);
35834                            $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'failed to update child card company.', $updateCCArr);
35835                            $dataSource->rollback();
35836                            $dataSource->commit();
35837                            return ;
35838                        }
35839                    }
35840                }
35841            }
35842
35843            // if light plan
35844            if ($formType == Configure::read('payment_lite_plan_upgrade') && $_allowChangePlan) {
35845                // check if user subscribed to zero student discount option
35846                $discountOptionData = $this->UserDiscountOptionsTerm->getTerm([
35847                    'user_id' =>  $userId,
35848                    'discount_option_id' => Configure::read('discount_option.zero_student.plan_id'),
35849                    'status' => 1
35850                ]);
35851
35852                // stop discount option
35853                if ($discountOptionData) {
35854                    // count successful discount
35855                    $discountCount = $this->DiscountOptionsSettlementHistory->countSuccessfulDiscount($discountOptionData['discount_option_term_id']);
35856                    
35857                    // open tunnel
35858                    myTools::initializeApiTunnel(['DiscountOptionController']);
35859
35860                    // initialize controller
35861                    $doc = new DiscountOptionController();
35862
35863                    $doshStatus = $discountCount ?
35864                        Configure::read('discount_option.dosh_status.midterm_cancellation') :
35865                        Configure::read('discount_option.dosh_status.maturity_cancellation');
35866
35867                    $szsdoParams = [
35868                        'discountOptionId' => $discountOptionData['discount_option_id'],
35869                        'discountOptionPriceId' => $discountOptionData['discount_option_price_id'],
35870                        'termId' => $discountOptionData['discount_option_term_id'],
35871                        'cancellationFee' => 0,
35872                        'cancellationType' => Configure::read('discount_option.dosh_type.plan_change'),
35873                        'userData' => $userData['User'],
35874                        'fromController' => $this->request->params['controller'],
35875                        'fromAction' => $this->request->params['action'],
35876                        'doshStatus' => $doshStatus
35877                    ];
35878
35879                    // set data
35880                    $doc->params = $szsdoParams;
35881
35882                    // stop
35883                    $stopDiscountOption = json_decode($doc->stopDiscountOption(), true);
35884
35885                    if (isset($stopDiscountOption['error']) && $stopDiscountOption['error']) {
35886                        $this->log(__METHOD__ . 'failed to stop zero student discount option: '.json_encode($szsdoParams), 'family_plan');
35887                        $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'failed to stop zero student discount option.', $szsdoParams);
35888                        return ;
35889                    }
35890                }
35891            }
35892
35893            $ptStatus = 1; // success
35894
35895            $dataSource->commit();
35896
35897            // - NJ-31307 : trigger campaign
35898            if(!empty($ptPaymentParams['nativeOptionPayment']) || !empty($ptPaymentParams['callanOptionPayment'])){
35899                ClassRegistry::init('CampaignSettingTable')->callanUnlimitedCampaign(array(
35900                    'user_id' => $userId, 
35901                    'trigger' => 3, 
35902                    'pt_params' => $ptData ?? [],
35903                    'payment_type' => 'Zeuspay'
35904                ));
35905            }
35906
35907
35908        } else {
35909            # possible fail transactions
35910            $inViableFailTransactions = array(
35911                Configure::read('payment_credit_monthly_payment'),
35912                Configure::read('payment_credit_coin_purchase'),
35913                Configure::read('payment_credit_receivable'),
35914                Configure::read('payment_credit_family_monthly_payment'),
35915                Configure::read('payment_native_option_join'),
35916                Configure::read('payment_native_option_monthly_payment'),
35917                Configure::read('payment_callan_option_join'),
35918                Configure::read('payment_callan_option_monthly_payment'),
35919                Configure::read('payment_lite_credit_monthly_payment')
35920            );
35921
35922            # if the form type is a possible fail transaction
35923            if (in_array($formType, $inViableFailTransactions)) {
35924                // return if existing user or new user failed to become family plan paid user
35925                if (
35926                    $formType == Configure::read('payment_credit_family_monthly_payment') && $familyId &&
35927                    isset($ptPaymentParams['new_family_plan']) && $ptPaymentParams['new_family_plan']
35928                ) {
35929                    $this->log(__METHOD__ . 'zeus.error.ng_return_applying_family: '.json_encode($data), 'family_plan');
35930                    $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'failed to update child card company.', $updateCCArr);
35931                    return ;
35932                }
35933
35934                # if form_type is for monthly payment
35935                if (
35936                    Configure::read('payment_credit_monthly_payment') == $formType ||
35937                    Configure::read('payment_credit_family_monthly_payment') == $formType ||
35938                    Configure::read('payment_lite_credit_monthly_payment') == $formType
35939                ) {
35940                    # set user data
35941                    $this->User->validate = array();
35942                    $userPrevData = $this->User->read(null, $userData['User']['id']);
35943                    if (!$userPrevData) {
35944                        $this->log(__METHOD__ . ' User id does not exist. ' . json_encode($userData), $logFileName);
35945                        $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'User id does not exist', $userData);
35946                        return ;
35947                    }
35948
35949                    //update user memo && native option cancellation time
35950                    $date = date('Y/m/d H:i:s');
35951                    $memoStr = $date." Cancellation of Native Speaker Unlimited option";
35952                    $memoStr2 = $date." Cancellation of Callan Unlimited option";
35953                    $updatedMemo = $memoStr."\n".$memoStr2."\n".$userPrevData['User']['memo'];
35954                    $userUpdate = array(
35955                        'fail_flg' => '1',
35956                        'counseling_attended_flg' => '1',
35957                        'charge_flg' => '0',
35958                        'allow_appreciation_flg' => '0',
35959                        'show_appreciation_flg' => '0',
35960                        'native_option' => 0,
35961                        'callan_option' => 0,
35962                        'next_charge_date' => NULL,
35963                        'memo' => $updatedMemo
35964                    );
35965
35966                    if (isset($userPrevData['User']['native_option']) && $userPrevData['User']['native_option']) {
35967                        $userUpdate['native_option_cancellation_time'] = $date;
35968                    }
35969
35970                    if (isset($userPrevData['User']['callan_option']) && $userPrevData['User']['callan_option']) {
35971                        $userUpdate['callan_option_cancellation_time'] = $date;
35972                    }
35973
35974                    $this->User->set($userUpdate);
35975                    if (!$this->User->save()) {
35976                        $this->log(__METHOD__ . ' Failed to update user data. ' . json_encode($userUpdate), $logFileName);
35977                        $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed to update user data', $userUpdate);
35978                        return ;
35979                    } else {
35980                        // check if has Native Option
35981                        if (isset($ptPaymentParams['nativeOptionPayment']) && $ptPaymentParams['nativeOptionPayment'] > 0) {
35982                            //NJ-2814 add logs
35983                            if (isset($ptPaymentParams['nativeOptionJoin']) && $ptPaymentParams['nativeOptionJoin']) {
35984                                $nativeStatus = 1; // subscribed
35985                                $statusBefore = $option_before_name = '';
35986                            } else {
35987                                $nativeStatus = 3; // unsubscribed
35988                                $statusBefore = 1;
35989                                $option_before_name = 'Native Unlimited Option';
35990                            }
35991
35992                            $optionLogParams = array(
35993                                'user_id' => $userId,
35994                                'platform' => $ptPaymentParams['platform'],
35995                                'status' => $nativeStatus,
35996                                'controller_name' => $this->request->params['controller'],
35997                                'action_name' => $this->request->params['action'],
35998                                'user_type' => 0, // user
35999                                'option_before' => $statusBefore,
36000                                'option_after' => 1,
36001                                'option_before_name' => $option_before_name,
36002                                'option_after_name' => '',
36003                                'option_type' => 1,
36004                                'payment_plan_id' => $paymentPlanId
36005                            );
36006
36007                            ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
36008                        }
36009
36010                        // check if has Callan Option
36011                        if (isset($ptPaymentParams['callanOptionPayment']) && $ptPaymentParams['callanOptionPayment'] > 0) {
36012                            //NJ-2814 add logs
36013                            if (isset($ptPaymentParams['callanOptionJoin']) && $ptPaymentParams['callanOptionJoin']) {
36014                                $callanStatus = 1; // subscribed
36015                                $statusBefore = $option_before_name = '';
36016                            } else {
36017                                $callanStatus = 3; // unsubscribed
36018                                $statusBefore = 1;
36019                                $option_before_name = 'Callan Unlimited Option';
36020                            }
36021
36022                            $optionLogParams = array(
36023                                'user_id' => $userId,
36024                                'platform' => $ptPaymentParams['platform'],
36025                                'status' => $callanStatus,
36026                                'controller_name' => $this->request->params['controller'],
36027                                'action_name' => $this->request->params['action'],
36028                                'user_type' => 0, // user
36029                                'option_before' => $statusBefore,
36030                                'option_after' => 1,
36031                                'option_before_name' => $option_before_name,
36032                                'option_after_name' => '',
36033                                'option_type' => 2,
36034                                'payment_plan_id' => $paymentPlanId
36035                            );
36036
36037                            ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
36038                        }
36039                    }
36040
36041                    # update user who join in ContinuationCampaign to fail status - 3
36042                    $this->ContinuationCampaign->setFailedUser(array(
36043                        'user_id' => $userData['User']['id']
36044                    ));
36045
36046                    // NJ-47740
36047                    // confiscate pending request coupon for native and callan option
36048                    $this->UsersCouponV1->confiscateOptionDiscount(array('userId' => $userId));
36049
36050                    // Get children list
36051                    $childList = $this->User->getChildId($userData['User']['id']);
36052
36053                    // check if user is parent 
36054                    if (!empty($childList)) {
36055                        foreach ($childList as $childId) {
36056                            // get child detail
36057                            $familyMember = $this->User->find('first', array(
36058                                'fields' => array(
36059                                    'User.id',
36060                                    'User.memo',
36061                                    'User.parent_id',
36062                                    'User.native_option',
36063                                    'User.callan_option'
36064                                ),
36065                                'conditions' => array('User.id' => $childId)
36066                            ));
36067                            $familyObj = new UserTable($familyMember['User']);
36068                            $addMemo = 'Family plan[User]: family deactivation parent failed settlement';
36069                            unset($familyObj->parent_id);
36070
36071                            // update children status to free
36072                            if ($this->User->updateStatusToFree($familyObj, $addMemo)) {
36073                                // - deactivate reserved lessons of the children
36074                                $this->LessonSchedule->deactivateDisableReservedLessons($childId, true, false, true, null, false, true);
36075
36076                                // NC-8645: add deactivation lock
36077                                UserTable::saveUserDeactivationLock($childId);
36078
36079                                // NC-5342: add deactivation log
36080                                $this->loadModel('FamilyDeactivationLog');
36081                                $this->FamilyDeactivationLog->addLog($childId);
36082                            }
36083
36084                            // NJ-47740
36085                            // confiscate pending request coupon for native and callan option
36086                            $this->UsersCouponV1->confiscateOptionDiscount(array('userId' => $childId));
36087                        }
36088                    }
36089                }
36090
36091                # set error code
36092                $data['error_code'] = Configure::read('zeus.error.ng_return');
36093                if (!$this->stripe_error_log_set($data, $ptPaymentParams)) {
36094                    $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, '_error_log_set failed', $data);
36095                    return ;
36096                }
36097            } else {
36098            }
36099
36100            if ($nativeOptionPayment > 0 && in_array($formType, array(Configure::read('payment_credit_monthly_payment'), Configure::read('payment_credit_family_monthly_payment')))) {
36101                $data['formType'] = Configure::read('payment_native_option_monthly_payment');
36102                $ptPaymentParams['paymentAmount'] = $nativeOptionPayment;
36103
36104                if (!$this->stripe_error_log_set($data, $ptPaymentParams)) {
36105                    $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, '_error_log_set failed', $data);
36106                    return ;
36107                }
36108            }
36109
36110            if ($callanOptionPayment > 0 && in_array($formType, array(Configure::read('payment_credit_monthly_payment'), Configure::read('payment_credit_family_monthly_payment')))) {
36111                $data['formType'] = Configure::read('payment_callan_option_monthly_payment');
36112                $ptPaymentParams['paymentAmount'] = $callanOptionPayment;
36113
36114                if (!$this->stripe_error_log_set($data, $ptPaymentParams)) {
36115                    $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, '_error_log_set failed', $data);
36116                    return ;
36117                }
36118            }
36119
36120            if (isset($ptPaymentParams['annualDiscountOption']) && $formType == Configure::read('payment_halfway_termination_of_annual_discount_option')) {
36121                if (!$this->stripe_error_log_set($data, $ptPaymentParams)) {
36122                    $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, '_error_log_set failed', $data);
36123                    return ;
36124                }
36125            }
36126
36127            if ($formType != Configure::read('payment_credit_authentication')) {
36128                $ptStatus = 2; // error;
36129            } else {
36130                $ptStatus = 0;
36131            }
36132        }
36133
36134        // update payment transaction
36135        $this->updatePaymentTransaction(array(
36136            'id' => $ptId,
36137            'fields' => array(
36138                'status' => $ptStatus,
36139                'response_text' => array('stripe_kickback' => $data)
36140            ),
36141            'logFileName' => $logFileName
36142        ));
36143
36144        // add registration bonus if user registration
36145        if (isset($ptPaymentParams['userRegister']) && $ptPaymentParams['userRegister']) {
36146
36147            if (isset($zeroStudentDiscount) && $zeroStudentDiscount) {
36148                UsersPointHistoryTable::checkDailyBonus($userId, true);
36149            } else {
36150                UsersPointHistoryTable::checkDailyBonus($userId);
36151            }
36152            if (
36153                (isset($ptPaymentParams['campaign95percentOff']) && $ptPaymentParams['campaign95percentOff'])
36154                || (time() >= strtotime(Configure::read('campaign_config.feb_new_registration.period.start')) && time() <= strtotime(Configure::read('campaign_config.feb_new_registration.period.end')))
36155            ) {
36156                $paramsRefBonus = array(
36157                    "type" => 1, // kickback
36158                    "userID" => $userId,
36159                    "userRegister" => true
36160                );
36161                // add referral coin NC-10009
36162                $this->User->addReferralBonus($paramsRefBonus);
36163            }
36164
36165            // - check if lite plan user 
36166            $this->User->clear();
36167            $_currentUser = $this->User->read(array('id','memo','payment_plan_id'), $userId);
36168            $_currentUserMemo = $_currentUser['User']['memo'];
36169
36170            if (in_array($_currentUser['User']['payment_plan_id'], Configure::read('lite_payment_plans'))) {
36171                # update user memo
36172                $_coins = Configure::read('credit.lite_plan_bonus_coin_authentication');
36173                if ($formType == Configure::read('payment_lite_credit_monthly_payment')) {
36174                    $_coins = Configure::read('lite_plan_monthly_coin');
36175                }
36176                $_dateNow = date('Y-m-d H:i:s');
36177                $_updateMemo =  "\n {$_dateNow} Light Plan Bonus: {$_coins}";
36178                $_updateMemo = $_updateMemo . "\n" . $_currentUserMemo;
36179
36180                // - update user memo 
36181                $this->User->clear();
36182                $memUpdateParams = array(
36183                    'id' => $userId,
36184                    'memo' => $_updateMemo
36185                );
36186                $this->User->set($memUpdateParams);
36187                $this->User->save();
36188            }
36189        }
36190
36191        // campaign master trigger 2
36192        if (
36193            strtoupper($data['result']) == 'OK' &&
36194            $formType == Configure::read('payment_credit_monthly_payment') && 
36195            $userData['User']['payment_plan_id'] == Configure::read('payment_plans.free_trial')
36196        ) {
36197            UsersPointTable::giveBonusCoins(['userId' => $userId, 'triggerNo' => 2]);
36198        }
36199
36200
36201        // campaign master trigger 5 
36202        if (strtoupper($data['result']) == 'OK') {
36203            $this->retrial_confiscate_coins([
36204                'formType' => $formType,
36205                'paymentPlanId' => $paymentPlanId,
36206                'userId' => $userId
36207            ]);
36208        }
36209
36210        // - NJ-18780 : lite plan
36211        if (
36212            strtoupper($data['result']) == 'OK' &&
36213            $formType == Configure::read('payment_lite_credit_monthly_payment') && 
36214            in_array($userData['User']['payment_plan_id'], Configure::read('lite_payment_plans'))
36215        ) {
36216            // confisacate and give monthly coin
36217
36218                // - fetch users mc coins
36219                $_monthlyPoints = $this->UsersPoint->getCurrentUserMCPoint($userId); //  mc coins
36220                $_dateNow = date('Y-m-d H:i:s');
36221                $_updateMemo = "";
36222
36223                if ((int) $_monthlyPoints > 0) {
36224                    $_confiscateParams = array(
36225                        'userId' => $userId,
36226                        'point' => $_monthlyPoints,
36227                        'kbn' => 18, // Administrator Change/Minus
36228                        'coinType' => 3
36229                    );
36230
36231                    $conficateLitePoints = $this->UsersPoint->confiscateUserLitePoints($_confiscateParams);
36232
36233                    if ($conficateLitePoints) {
36234                        $_updateMemo = $_updateMemo . "\n {$_dateNow} (Previous Coins (MC)【Confiscated】 : {$_monthlyPoints}. )";
36235                    }
36236                }
36237
36238                $_doneConfiscatePoints = ClassRegistry::init('UsersPointHistory')->confiscateUserLitePointsCoinBox($userId);
36239
36240                // update user memo 
36241                $_currentUser = $this->User->read(array('id','memo','next_charge_date'), $userId);
36242                $_nxtChargeDate = $_currentUser['User']['next_charge_date'];
36243                    
36244                // - set to add monthly coin
36245                $_pointParams = array(
36246                    'userId' => $userId,
36247                    'point' => Configure::read('lite_plan_monthly_coin'),
36248                    'kbn' => Configure::read('lite_plan_bonus_kbn'), // 
36249                    'kbnType' => 1, // add coin
36250                    'coinType' => 3, // mc coin
36251                    'dateExpiration' => $_nxtChargeDate,
36252                    'coinFailMessage' => Configure::read('coin.failed.membership')
36253                );
36254            
36255                // add user's points 
36256                $giveLitePoints = $this->UsersPoint->performPointTransaction($_pointParams);
36257
36258                if ($giveLitePoints) {
36259                    $_coins = Configure::read('lite_plan_monthly_coin');
36260                    $_updateMemo = $_updateMemo . "\n {$_dateNow} | Light Plan Bonus Coins (MC): {$_coins}";
36261                }
36262
36263        
36264                $_currentUserMemo = $_currentUser['User']['memo'];
36265
36266                if (!empty($_updateMemo)) {
36267                    $_updateMemo = $_updateMemo . "\n" . $_currentUserMemo;
36268                    $this->User->clear();
36269                    $this->User->set(array('id' => $userId,'memo' => $_currentUserMemo));
36270                    $this->User->save();
36271                }
36272        }
36273
36274        // send event to adjust
36275        if ($kbResult) {
36276            $adjustParams = array(
36277                'formType' => $formType,
36278                'statusBefore' => isset($ptPaymentParams['statusBefore']) ? $ptPaymentParams['statusBefore'] : null,
36279                'userId' => $userId,
36280                'idfa' => $userData['User']['idfa']
36281            );
36282            UserTable::sendEventToAdjust($adjustParams);
36283        }
36284
36285        //NJ-23626 continuing plan campaign
36286        if ((strtoupper($data['result']) == 'OK' || !empty($ptPaymentParams['coupon_used'])) && in_array($formType, array(Configure::read('payment_credit_retry'), Configure::read('payment_credit_monthly_payment')))){
36287            ClassRegistry::init('CampaignSettingTable')->takingLessonAndContinuePlan(array('user_id' => $userId, 'type' => 3));
36288        }
36289
36290    }
36291
36292    private function stripe_error_log_set($data = array(), $paymentParams = array()) {
36293        // set the variables
36294        $userId = isset($data['user_id']) ? $data['user_id'] : 0;
36295        $money = isset($paymentParams['paymentAmount']) ? $paymentParams['paymentAmount'] : 0;
36296        $sendId = isset($data['sendid']) ? $data['sendid'] : 0;
36297        $cardCompany = isset($data['metadata']['card_company']) ? $data['metadata']['card_company'] : Configure::read('card_company.stripe.apple');
36298        $formType = isset($data['formType']) ? $data['formType'] : 0;
36299        $result = array();
36300
36301        if ($userId && !$sendId) {
36302            $sendId = $userId;
36303        } elseif ($sendId && !$userId) {
36304            $userId = $sendId;
36305        }
36306
36307        $paymentType = isset($paymentParams['paymentType']) ? $paymentParams['paymentType'] : null;
36308        $priceId = isset($paymentParams['priceId']) ? $paymentParams['priceId'] : null;
36309        $paymentId = isset($paymentParams['paymentPlanId']) ? $paymentParams['paymentPlanId'] : null;
36310        $currencyCode = isset($paymentParams['currencyCode']) ? $paymentParams['currencyCode'] : Configure::read('currency_jpy');
36311        $discounted_amount = isset($paymentParams['discounted_amount']) ? $paymentParams['discounted_amount'] : 0;
36312
36313        // Check receivable type
36314        $cronDateRun = date("Y-m-d H:i:s");
36315        $receivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun);
36316        $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('appreciation_data.payment_element_type'));
36317        $liveReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.live'));
36318        $receivableFormTypeArr = array( Configure::read('payment_credit_receivable') );
36319        
36320        if( in_array( $formType, $receivableFormTypeArr ) ) {
36321            // Appreciation 
36322            if( $appreciationReceivable > 0 ) {
36323                $this->Payment->create();
36324                $this->Payment->set(array(
36325                    'user_id' => $userId,
36326                    'type_id' => 1,
36327                    'pay_kbn' => 1,
36328                    'form_type' => Configure::read('payment_credit_appreciation_receivable'),
36329                    'reference_id' => $sendId,
36330                    'amount' => $appreciationReceivable,
36331                    'card_company' => $cardCompany,
36332                    'param1' => json_encode($data),
36333                    'param2' => "error:" . $data['error_code'],
36334                    'currency_code' => $currencyCode,
36335                    'price_id' => $priceId,
36336                    'payment_id' => $paymentId,
36337                    'payment_type' => $paymentType,
36338                    'discounted_amount' => $discounted_amount
36339                ));
36340                $result[$formType][] = $this->Payment->save();
36341            }
36342
36343            // Live receivable 
36344            if( $liveReceivable > 0 ) {
36345                $this->Payment->create();
36346                $this->Payment->set(array(
36347                    'user_id' => $userId,
36348                    'type_id' => 1,
36349                    'pay_kbn' => 1,
36350                    'form_type' => Configure::read('payment_live_lesson_receivable'),
36351                    'reference_id' => $sendId,
36352                    'amount' => $liveReceivable,
36353                    'card_company' => $cardCompany,
36354                    'param1' => json_encode($data),
36355                    'param2' => "error:" . $data['error_code'],
36356                    'currency_code' => $currencyCode,
36357                    'price_id' => $priceId,
36358                    'payment_id' => $paymentId,
36359                    'payment_type' => $paymentType,
36360                    'discounted_amount' => $discounted_amount
36361                ));
36362                $res = $this->Payment->save();
36363
36364                if (!$res) {
36365                    CakeLog::debug(__METHOD__ . 'Error : saving live receivable -> params' . json_encode([$data, $paymentParams]));
36366                }
36367                $result[$formType][] = $res;
36368            }        
36369
36370            // Reservation
36371            if( $receivable > 0 ) {
36372                $this->Payment->create();
36373                $this->Payment->set(array(
36374                    'user_id' => $userId,
36375                    'type_id' => 1,
36376                    'pay_kbn' => 1,
36377                    'form_type' => Configure::read('payment_credit_receivable'),
36378                    'reference_id' => $sendId,
36379                    'amount' => $receivable,
36380                    'card_company' => $cardCompany,
36381                    'param1' => json_encode($data),
36382                    'param2' => "error:" . $data['error_code'],
36383                    'currency_code' => $currencyCode,
36384                    'price_id' => $priceId,
36385                    'payment_id' => $paymentId,
36386                    'payment_type' => $paymentType,
36387                    'discounted_amount' => $discounted_amount
36388                ));
36389                $result[$formType][] = $this->Payment->save();
36390            }
36391
36392        } else {
36393            if( $money > 0 ) {
36394                // save new payment row
36395                $this->Payment->create();
36396                $this->Payment->set(array(
36397                        'user_id' => $userId,
36398                        'type_id' => 1,
36399                        'pay_kbn' => 1,
36400                        'form_type' => $formType,
36401                        'reference_id' => $sendId,
36402                        'amount' => $money,
36403                        'card_company' => $cardCompany,
36404                        'param1' => json_encode($data),
36405                        'param2' => "error:" . $data['error_code'],
36406                        'currency_code' => $currencyCode,
36407                        'price_id' => $priceId,
36408                        'payment_id' => $paymentId,
36409                        'payment_type' => $paymentType,
36410                        'discounted_amount' => $discounted_amount
36411                ));
36412
36413                $result[$formType] = $this->Payment->save();
36414
36415                $annualDiscountOption = isset($paymentParams['annualDiscountOption']) ? $paymentParams['annualDiscountOption'] : [];
36416                // check if user plan has annual discount option
36417                if ($annualDiscountOption) {
36418                    // set data for discount option settlement history
36419                    $doshData = [
36420                        'user_id' => $userId,
36421                        'discount_option_term_id' => $annualDiscountOption['discount_option_term_id'],
36422                        'discount_option_id' => $annualDiscountOption['discount_option_id'],
36423                        'payment_id' => $this->Payment->id,
36424                        'discount_option_price_id' => $annualDiscountOption['discount_option_price_id'],
36425                        'payment_id' => $this->Payment->id,
36426                        'event' => $annualDiscountOption['dosh_event'],
36427                        'amount' => $annualDiscountOption['amount'],
36428                        'currency_code' => $currencyCode,
36429                        'type' => isset($annualDiscountOption['dosh_type']) ? $annualDiscountOption['dosh_type'] : null,
36430                        'status' => $annualDiscountOption['dosh_status'],
36431                        'settlement_status' => 0 // failed
36432                    ];
36433
36434                    // create discount option settlement history
36435                    if (!$res = $this->DiscountOptionsSettlementHistory->createHistory($doshData)) {
36436                    }
36437
36438                    $result[$formType][] = $res;
36439                }
36440            }
36441        }
36442    
36443        return $result;
36444        
36445    }
36446
36447
36448
36449    private function slackStripeErrorPostMsg($type = '', $line = '', $method = '', $userId = '', $failMessage='', $debugData = array(), $moreDebugData = array()) {
36450        $mySlack = new mySlack();
36451        $mySlack->channel = myTools::checkChannel("#nc-settlement", "#nc-settlement-dev");
36452        $mySlack->username = "NC Stripe Payment Failed";
36453        $mySlack->text = "```";
36454        $mySlack->text .= "ROLLBACK TYPE:\n";
36455        $mySlack->text .= $type . "\n\n";
36456        $mySlack->text .= "LINE NUMBER:\n";
36457        $mySlack->text .= $line . "\n\n";
36458        $mySlack->text .= "METHOD:\n";
36459        $mySlack->text .= $method . "\n\n";
36460        $mySlack->text .= "USER ID:\n";
36461        $mySlack->text .= $userId . "\n\n";
36462        $mySlack->text .= "KICKBACK URL:\n";
36463        $mySlack->text .= $_SERVER['REQUEST_URI'] . "\n\n";
36464        $mySlack->text .= "EC2 INSTANCE ID:\n";
36465        $mySlack->text .= exec('ec2-metadata -i') . "\n\n";
36466        $mySlack->text .= "REASON OF FAILURE:\n";
36467        $mySlack->text .= date("Y-m-d H:i:s") . " " . $failMessage."\n";
36468        $mySlack->text .= json_encode($debugData);
36469        if (!empty($moreDebugData)) {
36470            $mySlack->text .= "\n" . json_encode($moreDebugData);
36471        }
36472        $mySlack->text .= "```";
36473        $mySlack->sendSlack();
36474    }
36475
36476
36477    public function getStripeHostedPage() {
36478        $this->layout = '';
36479        $logFileName = isset($this->request->data['logFileName']) ? $this->request->data['logFileName'] : 'debug';
36480
36481        if ($this->request->is('post')) {
36482            $postData = $this->request->data;
36483
36484            // throw exception if there is/are missing parameter(s)
36485            if (
36486                !isset($postData['logFileName']) ||
36487                !isset($postData['apiToken']) ||
36488                !isset($postData['formType']) ||
36489                !isset($postData['successUrl']) ||
36490                !isset($postData['paymentMethodType']) ||
36491                !isset($postData['memKeyError']) ||
36492                !isset($postData['referrer']) ||
36493                (
36494                    empty(trim($postData['apiToken'])) &&
36495                    $postData['apiToken'] !== 0 &&
36496                    $postData['apiToken'] !== '0'
36497                )
36498            ) {
36499                $this->log(__METHOD__ . ' Missing parameters. post data --> ' . json_encode($postData), $logFileName);
36500                throw new BadRequestException("Missing parameter(s).");
36501            }
36502
36503            // set variables
36504            $apiToken = $postData['apiToken'];
36505            $formType = $postData['formType'];
36506            $successUrl = urldecode($postData['successUrl']);
36507            $paymentMethodType = $postData['paymentMethodType'];
36508            $nominalAmountArr = Configure::read('stripe.nominal_amount');
36509            $memKeyError = $postData['memKeyError'];
36510            $referrer = $postData['referrer'];
36511            $status = 0; // default pending
36512            $currencyExponents = Configure::read('stripe.currency_exponents');
36513            $exponent = $currencyExponents[$currencyCode];
36514
36515            $userParams = array(
36516                'fields' => array(
36517                    'User.id',
36518                    'User.email',
36519                    'User.nickname',
36520                    'User.card_token',
36521                    'User.charge_flg',
36522                    'User.fail_flg',
36523                    'User.currency_code',
36524                    'User.payment_plan_id',
36525                    'User.price_id',
36526                    'User.double_check_flg',
36527                    'User.status',
36528                    'User.complimentary_code',
36529                    'User.card_company',
36530                    'User.phone_number',
36531                    'PaymentPlanPrice.amount'
36532            ),
36533                'apiToken' => $apiToken
36534            );
36535
36536            // throw exception if api token not exist
36537            if (!$userData = $this->User->getWPMobappUserData($userParams)) {
36538                $this->log(__METHOD__ . ' User api token does not exist. User params --> ' . json_encode($userParams), $logFileName);
36539                throw new InternalErrorException("User api token does not exist.");
36540            }
36541
36542            $userCurrencyCode = $userData['User']['currency_code'];
36543            $complimentaryCode = $userData['User']['complimentary_code'];
36544
36545            // NC-9168: override currency if worldpay card auth and JPY currency
36546            $expectedUserCurrency = $this->allowedCurrencies[$this->localizeDir];
36547            if (isset($postData['ncTerminalType']) && $postData['ncTerminalType'] == 1 &&
36548                $formType == Configure::read('payment_credit_authentication') && $userData['User']['currency_code'] != $expectedUserCurrency) {
36549                // Get localized language equivalent currency code
36550                if (
36551                    isset($this->localizeDir) && 
36552                    in_array($this->localizeDir, array_keys($this->allowedCurrencies)) &&
36553                    // do not update currency_code if user account has complimentary code
36554                    empty($complimentaryCode)
36555                ) {
36556                    $userCurrencyCode = $this->allowedCurrencies[$this->localizeDir];
36557                    // NC-9629: do not override if JPY
36558                    if ($userCurrencyCode == Configure::read('default.user_currency')) {
36559                    } else {
36560                        $this->User->validate = array();
36561                        $this->User->read(array('currency_code'), $userData['User']['id']);
36562                        $this->User->set(array('currency_code' => $userCurrencyCode));
36563                        $this->User->save();
36564                    }
36565                }
36566            }
36567
36568            // set variables
36569            $paymentPlanPriceAmount = $userData['PaymentPlanPrice']['amount'];
36570            $userData = $userData['User'];
36571            $currencyCode = $userCurrencyCode;
36572            $paymentPlanId = $userData['payment_plan_id'];
36573            $priceId = $userData['price_id'];
36574            $userId = $userData['id'];
36575            $preToken = $userData['card_token'];
36576            $discounted_amount = isset($userData['discounted_amount']) ?? 0;
36577            $totalAmountArr = myTools::wpGetAmount($exponent, $nominalAmountArr[$currencyCode]);
36578            $ncPaymentAmount = 0;
36579            $stripePaymentAmount = $totalAmountArr['wpAmount'];
36580
36581
36582            // get payment method (debit or credit)
36583            $paymentMethod = 'stripe';
36584
36585            switch ($formType) {
36586                case Configure::read('payment_credit_authentication'):
36587                    $tokenReason = 'Payment Credit Registration';
36588                    if (!isset($priceId)) {
36589                        // get payment data
36590                        $paymentData = $this->PaymentPlanPrice->getPaymentData(array(
36591                            'currencyCode' => $currencyCode,
36592                            'paymentPlanId' => Configure::read('payment_plans.free_trial'),
36593                            'logFileName' => $logFileName
36594                        ));
36595
36596                        // throw error exception if does not exist
36597                        if (!$paymentData) {
36598                            throw new InternalErrorException("Payment plan does not exist.");
36599                        }
36600
36601                        $priceId = $paymentData['priceId'];
36602                    }
36603                    $paymentPlanId = Configure::read('payment_plans.free_trial');
36604                    break;
36605                case Configure::read('payment_credit_change'):
36606                    if (!isset($priceId) || !isset($paymentPlanId)) {
36607                        throw new InternalErrorException("Price id or payment plan id is/are empty.");
36608                    }
36609
36610                    // add reserve payment amount
36611                    $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userId);
36612
36613                    // add appreciation lesson amount
36614                    $receivablePayment += $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.appreciation'));
36615
36616                    // add live lesson amount
36617                    $receivablePayment += $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.live'));
36618
36619                    // change payment method type to payment, if has receivable payment
36620                    if ($receivablePayment > 0) {
36621                        $paymentMethodType = $paymentMethod . '_payment';
36622                        $wpPaymentAmount = $ncPaymentAmount = $receivablePayment;
36623                    }
36624                    
36625                    $tokenReason = 'Payment Credit Change';
36626                    break;
36627                case Configure::read('payment_credit_retry'):
36628                    // get payment data
36629                    if (!$paymentData = $this->getRetryPaymentData($userData, $logFileName)) {
36630                        throw new InternalErrorException("Payment plan does not exist.");
36631                    }
36632
36633                    $stripePaymentAmount = $paymentData['amount'];
36634                    $priceId = $paymentData['priceId'];
36635                    $paymentPlanId = $paymentData['paymentPlanId'];
36636                    
36637                    // NJ-47740 - get monthly reqeust coupon discount
36638                    $coupon = $this->UsersCouponV1->getCouponUseRequest(array(
36639                        'userId' => $userId,
36640                        'kbn' => Configure::read('coupon_kbn.monthly_settlement')
36641                    ));
36642                    
36643                    if (!empty($coupon['amount']) && !empty($coupon['grp_id'])) {
36644                        
36645                        if ($coupon['amount'] >= $stripePaymentAmount) {
36646                            $userData['monthlyDiscount'] = $stripePaymentAmount;
36647                            $stripePaymentAmount = 0;
36648                        } else {
36649                            $stripePaymentAmount -= $userData['monthlyDiscount'] = $coupon['amount'];
36650                        }
36651                        $userData['monthly_grp_id'] = $coupon['grp_id'];
36652                    }
36653
36654                    // add reserve payment amount
36655                    $stripePaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment($userId);
36656
36657                    // add appreciation lesson amount
36658                    $stripePaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.appreciation'));
36659
36660                    // add live lesson amount
36661                    $stripePaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.live'));
36662
36663                    $ncPaymentAmount = $stripePaymentAmount;
36664
36665                    // change payment method type to auth if amount to be paid in is equal to 0
36666                    if ($stripePaymentAmount == 0) {
36667                        $paymentMethodType = $paymentMethod . '_auth';
36668                        $stripePaymentAmount = $nominalAmountArr[$currencyCode];
36669                    }
36670
36671                    $tokenReason = 'Payment Credit Retry';
36672                    break;
36673                case Configure::read('payment_credit_force_charge'):
36674                    // get payment data
36675                    $paymentData = $this->PaymentPlanPrice->getPaymentData(array(
36676                        'currencyCode' => $currencyCode,
36677                        'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
36678                        'logFileName' => $logFileName
36679                    ));
36680
36681                    // throw error exception if does not exist
36682                    if (!$paymentData) {
36683                        throw new InternalErrorException("Payment plan does not exist.");
36684                    }
36685
36686                    $stripePaymentAmount = $paymentData['amount'];
36687                    $priceId = $paymentData['priceId'];
36688                    $paymentPlanId = $paymentData['paymentPlanId'];
36689
36690                    // add reserve payment amount
36691                    $stripePaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment($userId);
36692
36693                    // add live lesson payment amount
36694                    $stripePaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment( $userId, false, Configure::read('appreciation_data.payment_element_type') );
36695
36696                    // add live lesson payment amount
36697                    $stripePaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.live'));                    
36698
36699                    $ncPaymentAmount = $stripePaymentAmount;
36700
36701                    // change payment method type to auth if amount is  equal to 0
36702                    if ($stripePaymentAmount == 0) {
36703                        $paymentMethodType = $paymentMethod . '_auth';
36704                        $totalAmountArr = myTools::wpGetAmount($exponent, $nominalAmountArr[$currencyCode]);
36705                        $stripePaymentAmount = $totalAmountArr['wpAmount'];
36706                    } else {
36707                        $totalAmountArr = myTools::wpGetAmount($exponent, $stripePaymentAmount);
36708                        $ncPaymentAmount = $totalAmountArr['ncAmount'];
36709                        $stripePaymentAmount = $totalAmountArr['wpAmount'];
36710                    }
36711
36712                    $tokenReason = 'Payment Credit Charge';
36713                    break;
36714            }
36715
36716            $orderNumber = myTools::generateOrderCode($userId);
36717
36718            // before coupon settlement amount deduction
36719            $beforeCouponSettlementAmount = $ncPaymentAmount;
36720
36721            // NJ-32737
36722            $couponData = $this->Session->read('apply_coupon_usage_data');
36723
36724            $membershipStatusIndex = UserTable::getStudentMembershipStatus($userId);
36725            if (in_array($membershipStatusIndex, Configure::read('allow_coupon.settlement')) &&
36726                isset($formType) &&
36727                in_array($formType, Configure::read('allow_coupon.settlement_form_type'))
36728            ) {
36729                // confiscate the coupon pending request when student is re-enrolled
36730                $res_confiscate = $this->UsersCouponV1->confiscateAllCoupon(array(
36731                    'userId' => $userId,
36732                    'action_type' => 1 // only the pending request will be confiscated
36733                ));
36734                
36735                if (!$res_confiscate) {
36736                    $this->log(__METHOD__ . ' Failed to confiscate coupon pending request. User id --> ' . $userId, $logFileName);
36737                }
36738
36739                if (isset($couponData['useCouponAmount']) && $couponData['useCouponAmount'] > 0) {
36740                    if ($stripePaymentAmount >= $couponData['useCouponAmount']) {
36741                        $stripePaymentAmount -= $couponData['useCouponAmount'];
36742                        $ncPaymentAmount -= $couponData['useCouponAmount'];
36743                    } else {
36744                        $stripePaymentAmount = 0;
36745                        $ncPaymentAmount = 0;
36746                    }
36747
36748                    // change niminal amount if amount is  equal to 0
36749                    if ($stripePaymentAmount == 0) {
36750                        $stripePaymentAmount = $nominalAmountArr[$currencyCode];
36751                    }
36752
36753                    $couponUseSettlement = $couponData;
36754                }
36755            }
36756            // NJ-32737-end
36757
36758            // get total amount with checking currency exponent
36759            $totalAmountArr = myTools::wpGetAmount($exponent, $stripePaymentAmount);
36760            $stripePaymentAmount = $totalAmountArr['wpAmount'];
36761
36762
36763            $paymentParams = array(
36764                'currencyCode' => $currencyCode,
36765                'formType' => $formType,
36766                'logFileName' => $logFileName,
36767                'remoteAddress' => $_SERVER["REMOTE_ADDR"],
36768                'cardToken' => isset($userData['card_token']) ? $userData['card_token'] : null,
36769                'newCard' => true,
36770                'stripePaymentAmount' => $stripePaymentAmount,
36771                'paymentAmount' => $ncPaymentAmount,
36772                'priceId' => $priceId,
36773                'paymentPlanId' => $paymentPlanId,
36774                'paymentType' => Configure::read('payment_types.payment_plan')
36775            );
36776
36777            if (!empty($couponUseSettlement)) {
36778                $paymentParams['couponUseSettlement'] = $couponUseSettlement;
36779            }
36780            
36781            if (!empty($coupon) && isset($formType) && $formType == Configure::read('payment_credit_retry') && !empty($userData['monthlyDiscount']) && !empty($userData['monthly_grp_id'])) {
36782                $paymentParams['discounted_amount'] = $userData['monthlyDiscount'];
36783                $paymentParams['monthlyDiscount'] = $userData['monthlyDiscount'];
36784                $paymentParams['monthly_grp_id'] = $userData['monthly_grp_id'];
36785            }
36786
36787            if (isset($postData['userRegister']) && $postData['userRegister']) {
36788                $paymentParams['userRegister'] = true;
36789            }
36790
36791            // NJ-42971: free trial checker
36792            $notFreeTrial = true;
36793
36794            if ($formType != Configure::read('payment_credit_change')) {
36795                $membershipTypes = UserTable::getEngMembershipTypeData();
36796                $statusAfter = $membershipTypes[1]; // premium plan paid
36797
36798                /* -- get before status -- */
36799                if ($this->memcache->get('com_plan_user_' . $userId) && $userData && $userData['payment_plan_id'] == Configure::read('payment_plans.complimentary_plan')) {
36800                    $statusBefore = $membershipTypes[15]; // complimentary code
36801                    $paymentParams['bonusCoinFlg'] = 1;
36802                    $paymentParams['updateFirstChargeDate'] = true;
36803                } elseif ($userData['charge_flg'] == 0) {
36804                    // failed settlement
36805                    if ($userData['fail_flg'] == 1) {
36806                        $statusBefore = $membershipTypes[5];
36807                    // trial again
36808                    } elseif ($userData['fail_flg'] == 0 && $userData['double_check_flg'] == 1) {
36809                        $statusBefore = $membershipTypes[13];
36810                        $notFreeTrial = false;
36811                    // unsubscribed
36812                    } elseif ($userData['fail_flg'] == 0 && $userData['double_check_flg'] == 2) {
36813                        $statusBefore = $membershipTypes[12];
36814                    // temporary
36815                    } elseif ($userData['status'] == 0) {
36816                        $statusBefore = $membershipTypes[6];
36817                        $statusAfter = $membershipTypes[2]; // premium plan free
36818                    } else {
36819                        $statusBefore = null;
36820                    }
36821                }
36822
36823                if (isset($statusBefore)) {
36824                    $user = new UserTable($userData);
36825                    $membershipTypeIndex = $user->getMembershipTypeIndex();
36826
36827                    if ($membershipTypeIndex == 13) {
36828                        $statusBefore = $membershipTypes[13];
36829                        $paymentParams['userRegister'] = true;
36830                        $notFreeTrial = false;
36831                        $statusAfter = $membershipTypes[2];
36832                    }
36833
36834                    // get platform use
36835                    $platform = myTools::mobappDetectPlatform();
36836                    $paymentParams['platform'] = $platform == Configure::read('platform.splp') ? Configure::read('platform.pclp') : $platform;
36837                    $paymentParams['statusBefore'] = $statusBefore;
36838                    $paymentParams['statusAfter'] = $statusAfter;
36839
36840                    $user = new UserTable($userData);
36841                    $membershipTypeIndex = $user->getMembershipTypeIndex();
36842
36843                    if ($membershipTypeIndex == 13) {
36844                        $paymentParams['userRegister'] = true;
36845                    }
36846                }
36847            }
36848
36849            $ptParams = array(
36850                'user_id' => $userId,
36851                'payment_hash' => $orderNumber,
36852                'status' => $status,
36853                'payment_params' => json_encode($paymentParams),
36854                'course_id' => Configure::read("credit.course_id")
36855            );
36856
36857            // throw exception if failed to save payment transaction
36858            if (!$pt = $this->PaymentTransaction->setWPPaymentTransaction($ptParams)) {
36859                $this->log(__METHOD__ .' Failed to save payment transaction. update data --> ' . json_encode($result), $logFileName);
36860                throw new InternalErrorException("Failed to save payment transaction.");
36861            }
36862
36863            $this->Session->write('wp_coupon_settlement_payment', [
36864                'payment_hash' => $pt['payment_hash'],
36865                'payment_amount' => $beforeCouponSettlementAmount // set before coupon settlement amount
36866            ]);
36867
36868            $this->set('logFileName', $logFileName);
36869            $this->set('apiToken', $apiToken);
36870            $this->set('orderNumber', $orderNumber);
36871            $this->set('userId', $userId);
36872            $this->set('salesSettled', $auth ? 'false' : 'true');
36873            $this->set('stripePaymentAmount', $stripePaymentAmount);
36874            $this->set('ncPaymentAmount', $ncPaymentAmount);
36875            $this->set('transactionOptions', $auth);
36876            $this->set('nc_terminal_type', isset($postData['ncTerminalType']) ? $postData['ncTerminalType'] : 0);
36877            $this->set('formType', $formType);
36878            $this->set('memKeyError', 'card_regist_error_'.$apiToken);
36879            $this->set('referrer', $postData['referrer']);
36880            $this->set('successUrl', $successUrl);
36881            $this->set('userRegister', true);
36882            $this->set('ptID', $pt['id']);
36883            $this->set('preToken', $preToken);
36884        } else {
36885            throw new MethodNotAllowedException("Method used is not POST.");
36886        }
36887
36888        $this->render('/Elements/mobapp/stripe_get_hosted_page');
36889    }
36890
36891
36892    private function sendStripeResponseSlackMessage($params) {
36893        // - add response
36894        $mySlack = new mySlack();
36895        $mySlack->allow_test_channel = true;
36896        $mySlack->channel = myTools::checkChannel("#nj-agpay-results", "#nj-agpay-results");
36897        $mySlack->username = "STRIPE PAYMENT EVENT";
36898        $mySlack->link_names = true;
36899        $mySlack->token = "xoxb-392902820692-6499139810404-RHHGc6Z5ZB9o2KkiGhzTTtlQ";
36900        $mySlack->text = "```";
36901        $mySlack->text .= "user_id: " . $params['userId'] . "\n\n";
36902        if(isset($params['payment_hash']) && $params['payment_hash']) {
36903            $mySlack->text .= "payment_hash: " . $params['paymentHash'] ."\n\n";
36904        }
36905        $mySlack->text .= "action: " . $params['action'] ."\n\n";
36906        $mySlack->text .= "request: " . json_encode($params['request']) ."\n\n";
36907        $mySlack->text .= "response: " . json_encode($params['response']) ."\n\n";
36908        if(isset($params['error_msg']) && $params['error_msg']) {
36909            $mySlack->text .= "error: " . $params['error_msg'] ."\n\n";
36910        }
36911        $mySlack->text .= "```";
36912        $mySlack->postMessage();
36913    }
36914
36915    /**
36916     * NC-62324: Update user Token
36917     * @param array $params
36918     * @return array $res
36919     */
36920    private function updateUserToken($params = array()) {
36921        $result = wpPaymentService::updateUserToken($params['updateTokenParams']);
36922        $updateToken = isset($result['paymentService']['reply']['ok']['updateTokenReceived']) ? true : false;
36923
36924        // log if failed to delete token in wp
36925        if (!$updateToken) {
36926            $this->log(__METHOD__ . ' Failed to udpate user wp card token. params --> ' . json_encode($params['updateTokenParams']) . ", error(s) --> " . $deleteTokenResultJson .' | kickback data --> ' . $params['dataJson'], $params['logFileName']);
36927        }
36928
36929        return $result;
36930    }
36931}